From 1b9e94dc69959e963fe57ede46259f792641af4d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 Sep 2012 09:23:31 -0300 Subject: [media] bttv: add VIDIOC_DBG_G_CHIP_IDENT VIDIOC_DBG_G_CHIP_IDENT is a prerequisite for the G/S_REGISTER ioctls. In addition, add support to call G/S_REGISTER for supporting i2c devices. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-chip-ident.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 4ee125bae719..b5996f959a31 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -96,12 +96,20 @@ enum { /* module au0828 */ V4L2_IDENT_AU0828 = 828, + /* module bttv: ident 848 + 849 */ + V4L2_IDENT_BT848 = 848, + V4L2_IDENT_BT849 = 849, + /* module bt856: just ident 856 */ V4L2_IDENT_BT856 = 856, /* module bt866: just ident 866 */ V4L2_IDENT_BT866 = 866, + /* module bttv: ident 878 + 879 */ + V4L2_IDENT_BT878 = 878, + V4L2_IDENT_BT879 = 879, + /* module ks0127: reserved range 1120-1129 */ V4L2_IDENT_KS0122S = 1122, V4L2_IDENT_KS0127 = 1127, -- cgit v1.2.3 From 01df530c2791610727e345b3dd97ef75943c7320 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:40:28 -0300 Subject: [media] bttv: convert to the control framework Note that the private chroma agc control has been replaced with the standard CHROMA_AGC control. Also fixes a mute/automute problem where closing the file handle would force mute on. That's not what you want since that would make the mute state out of sync with the mute control. Instead check against the user count. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-cards.c | 5 +- drivers/media/pci/bt8xx/bttv-driver.c | 682 +++++++++++++--------------------- drivers/media/pci/bt8xx/bttvp.h | 16 +- include/uapi/linux/v4l2-controls.h | 5 + 4 files changed, 271 insertions(+), 437 deletions(-) (limited to 'include') diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index c4c59175e52c..682ed893d718 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -3554,8 +3554,9 @@ void bttv_init_card2(struct bttv *btv) I2C_CLIENT_END }; - if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tda7432", 0, addrs)) + btv->sd_tda7432 = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tda7432", 0, addrs); + if (btv->sd_tda7432) return; } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 73404b7a1396..8e0a44d03fc4 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -94,7 +94,7 @@ static unsigned int combfilter; static unsigned int lumafilter; static unsigned int automute = 1; static unsigned int chroma_agc; -static unsigned int adc_crush = 1; +static unsigned int agc_crush = 1; static unsigned int whitecrush_upper = 0xCF; static unsigned int whitecrush_lower = 0x7F; static unsigned int vcr_hack; @@ -126,7 +126,7 @@ module_param(combfilter, int, 0444); module_param(lumafilter, int, 0444); module_param(automute, int, 0444); module_param(chroma_agc, int, 0444); -module_param(adc_crush, int, 0444); +module_param(agc_crush, int, 0444); module_param(whitecrush_upper, int, 0444); module_param(whitecrush_lower, int, 0444); module_param(vcr_hack, int, 0444); @@ -139,27 +139,27 @@ module_param_array(video_nr, int, NULL, 0444); module_param_array(radio_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)"); -MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian"); -MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)"); -MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)"); -MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)"); -MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)"); +MODULE_PARM_DESC(radio, "The TV card supports radio, default is 0 (no)"); +MODULE_PARM_DESC(bigendian, "byte order of the framebuffer, default is native endian"); +MODULE_PARM_DESC(bttv_verbose, "verbose startup messages, default is 1 (yes)"); +MODULE_PARM_DESC(bttv_gpio, "log gpio changes, default is 0 (no)"); +MODULE_PARM_DESC(bttv_debug, "debug messages, default is 0 (no)"); +MODULE_PARM_DESC(irq_debug, "irq handler debug messages, default is 0 (no)"); MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); -MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8"); -MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); -MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default " +MODULE_PARM_DESC(gbuffers, "number of capture buffers. range 2-32, default 8"); +MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 0x208000"); +MODULE_PARM_DESC(reset_crop, "reset cropping parameters at open(), default " "is 1 (yes) for compatibility with older applications"); -MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)"); -MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); -MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); -MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207"); -MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); -MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); -MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); -MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); -MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); -MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); +MODULE_PARM_DESC(automute, "mute audio on bad/missing video signal, default is 1 (yes)"); +MODULE_PARM_DESC(chroma_agc, "enables the AGC of chroma signal, default is 0 (no)"); +MODULE_PARM_DESC(agc_crush, "enables the luminance AGC crush, default is 1 (yes)"); +MODULE_PARM_DESC(whitecrush_upper, "sets the white crush upper value, default is 207"); +MODULE_PARM_DESC(whitecrush_lower, "sets the white crush lower value, default is 127"); +MODULE_PARM_DESC(vcr_hack, "enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); +MODULE_PARM_DESC(irq_iswitch, "switch inputs in irq handler"); +MODULE_PARM_DESC(uv_ratio, "ratio between u and v gains, default is 50"); +MODULE_PARM_DESC(full_luma_range, "use the full luma range, default is 0 (no)"); +MODULE_PARM_DESC(coring, "set the luma coring level, default is 0 (no)"); MODULE_PARM_DESC(video_nr, "video device numbers"); MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); MODULE_PARM_DESC(radio_nr, "radio device numbers"); @@ -169,6 +169,17 @@ MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); MODULE_LICENSE("GPL"); MODULE_VERSION(BTTV_VERSION); +#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_USER_BTTV_BASE + 0) +#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_USER_BTTV_BASE + 1) +#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_USER_BTTV_BASE + 2) +#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_USER_BTTV_BASE + 3) +#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_USER_BTTV_BASE + 4) +#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_USER_BTTV_BASE + 5) +#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_USER_BTTV_BASE + 6) +#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_USER_BTTV_BASE + 7) +#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_USER_BTTV_BASE + 8) +#define V4L2_CID_PRIVATE_CORING (V4L2_CID_USER_BTTV_BASE + 9) + /* ----------------------------------------------------------------------- */ /* sysfs */ @@ -622,198 +633,6 @@ static const struct bttv_format formats[] = { }; static const unsigned int FORMATS = ARRAY_SIZE(formats); -/* ----------------------------------------------------------------------- */ - -#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) -#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) -#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; -static const struct v4l2_queryctrl bttv_ctls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 27648, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_COLOR_KILLER, - .name = "Color killer", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BASS, - .name = "Bass", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_TREBLE, - .name = "Treble", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- private --- */ - { - .id = V4L2_CID_PRIVATE_CHROMA_AGC, - .name = "chroma agc", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_COMBFILTER, - .name = "combfilter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AUTOMUTE, - .name = "automute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_LUMAFILTER, - .name = "luma decimation filter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AGC_CRUSH, - .name = "agc crush", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_VCR_HACK, - .name = "vcr hack", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, - .name = "whitecrush upper", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0xCF, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, - .name = "whitecrush lower", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0x7F, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_UV_RATIO, - .name = "uv ratio", - .minimum = 0, - .maximum = 100, - .step = 1, - .default_value = 50, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, - .name = "full luma range", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_CORING, - .name = "coring", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } - - - -}; - -static const struct v4l2_queryctrl *ctrl_by_id(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) - if (bttv_ctls[i].id == id) - return bttv_ctls+i; - - return NULL; -} - /* ----------------------------------------------------------------------- */ /* resource management */ @@ -1173,7 +992,7 @@ static int audio_mux(struct bttv *btv, int input, int mute) { int gpio_val, signal; - struct v4l2_control ctrl; + struct v4l2_ctrl *ctrl; gpio_inout(bttv_tvcards[btv->c.type].gpiomask, bttv_tvcards[btv->c.type].gpiomask); @@ -1183,7 +1002,8 @@ audio_mux(struct bttv *btv, int input, int mute) btv->audio = input; /* automute */ - mute = mute || (btv->opt_automute && !signal && !btv->radio_user); + mute = mute || (btv->opt_automute && (!signal || !btv->users) + && !btv->radio_user); if (mute) gpio_val = bttv_tvcards[btv->c.type].gpiomute; @@ -1205,12 +1025,13 @@ audio_mux(struct bttv *btv, int input, int mute) if (in_interrupt()) return 0; - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = btv->mute; - bttv_call_all(btv, core, s_ctrl, &ctrl); if (btv->sd_msp34xx) { u32 in; + ctrl = v4l2_ctrl_find(btv->sd_msp34xx->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, btv->mute); + /* Note: the inputs tuner/radio/extern/intern are translated to msp routings. This assumes common behavior for all msp3400 based TV cards. When this assumption fails, then the @@ -1255,9 +1076,19 @@ audio_mux(struct bttv *btv, int input, int mute) in, MSP_OUTPUT_DEFAULT, 0); } if (btv->sd_tvaudio) { + ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE); + + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, btv->mute); v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, input, 0, 0); } + if (btv->sd_tda7432) { + ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE); + + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, btv->mute); + } return 0; } @@ -1395,8 +1226,6 @@ static void init_irqreg(struct bttv *btv) static void init_bt848(struct bttv *btv) { - int val; - if (bttv_tvcards[btv->c.type].no_video) { /* very basic init only */ init_irqreg(btv); @@ -1416,30 +1245,10 @@ static void init_bt848(struct bttv *btv) BT848_GPIO_DMA_CTL_GPINTI, BT848_GPIO_DMA_CTL); - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - btwrite(0x20, BT848_E_VSCALE_HI); btwrite(0x20, BT848_O_VSCALE_HI); - btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - btwrite(whitecrush_upper, BT848_WC_UP); - btwrite(whitecrush_lower, BT848_WC_DOWN); - - if (btv->opt_lumafilter) { - btwrite(0, BT848_E_CONTROL); - btwrite(0, BT848_O_CONTROL); - } else { - btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - - bt848_bright(btv, btv->bright); - bt848_hue(btv, btv->hue); - bt848_contrast(btv, btv->contrast); - bt848_sat(btv, btv->saturation); + v4l2_ctrl_handler_setup(&btv->ctrl_handler); /* interrupt */ init_irqreg(btv); @@ -1461,103 +1270,26 @@ static void bttv_reinit_bt848(struct bttv *btv) set_input(btv, btv->input, btv->tvnorm); } -static int bttv_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) +static int bttv_s_ctrl(struct v4l2_ctrl *c) { - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = btv->bright; - break; - case V4L2_CID_HUE: - c->value = btv->hue; - break; - case V4L2_CID_CONTRAST: - c->value = btv->contrast; - break; - case V4L2_CID_SATURATION: - c->value = btv->saturation; - break; - case V4L2_CID_COLOR_KILLER: - c->value = btv->opt_color_killer; - break; - - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, g_ctrl, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - c->value = btv->opt_chroma_agc; - break; - case V4L2_CID_PRIVATE_COMBFILTER: - c->value = btv->opt_combfilter; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - c->value = btv->opt_lumafilter; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - c->value = btv->opt_automute; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - c->value = btv->opt_adc_crush; - break; - case V4L2_CID_PRIVATE_VCR_HACK: - c->value = btv->opt_vcr_hack; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - c->value = btv->opt_whitecrush_upper; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - c->value = btv->opt_whitecrush_lower; - break; - case V4L2_CID_PRIVATE_UV_RATIO: - c->value = btv->opt_uv_ratio; - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - c->value = btv->opt_full_luma_range; - break; - case V4L2_CID_PRIVATE_CORING: - c->value = btv->opt_coring; - break; - default: - return -EINVAL; - } - return 0; -} - -static int bttv_s_ctrl(struct file *file, void *f, - struct v4l2_control *c) -{ - int err; - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (0 != err) - return err; + struct bttv *btv = container_of(c->handler, struct bttv, ctrl_handler); + int val; switch (c->id) { case V4L2_CID_BRIGHTNESS: - bt848_bright(btv, c->value); + bt848_bright(btv, c->val); break; case V4L2_CID_HUE: - bt848_hue(btv, c->value); + bt848_hue(btv, c->val); break; case V4L2_CID_CONTRAST: - bt848_contrast(btv, c->value); + bt848_contrast(btv, c->val); break; case V4L2_CID_SATURATION: - bt848_sat(btv, c->value); + bt848_sat(btv, c->val); break; case V4L2_CID_COLOR_KILLER: - btv->opt_color_killer = c->value; - if (btv->opt_color_killer) { + if (c->val) { btor(BT848_SCLOOP_CKILL, BT848_E_SCLOOP); btor(BT848_SCLOOP_CKILL, BT848_O_SCLOOP); } else { @@ -1566,36 +1298,22 @@ static int bttv_s_ctrl(struct file *file, void *f, } break; case V4L2_CID_AUDIO_MUTE: - audio_mute(btv, c->value); - /* fall through */ - case V4L2_CID_AUDIO_VOLUME: - if (btv->volume_gpio) - btv->volume_gpio(btv, c->value); - - bttv_call_all(btv, core, s_ctrl, c); + audio_mute(btv, c->val); break; - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, s_ctrl, c); + case V4L2_CID_AUDIO_VOLUME: + btv->volume_gpio(btv, c->val); break; - case V4L2_CID_PRIVATE_CHROMA_AGC: - btv->opt_chroma_agc = c->value; - if (btv->opt_chroma_agc) { - btor(BT848_SCLOOP_CAGC, BT848_E_SCLOOP); - btor(BT848_SCLOOP_CAGC, BT848_O_SCLOOP); - } else { - btand(~BT848_SCLOOP_CAGC, BT848_E_SCLOOP); - btand(~BT848_SCLOOP_CAGC, BT848_O_SCLOOP); - } + case V4L2_CID_CHROMA_AGC: + val = c->val ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); break; case V4L2_CID_PRIVATE_COMBFILTER: - btv->opt_combfilter = c->value; + btv->opt_combfilter = c->val; break; case V4L2_CID_PRIVATE_LUMAFILTER: - btv->opt_lumafilter = c->value; - if (btv->opt_lumafilter) { + if (c->val) { btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); } else { @@ -1604,36 +1322,31 @@ static int bttv_s_ctrl(struct file *file, void *f, } break; case V4L2_CID_PRIVATE_AUTOMUTE: - btv->opt_automute = c->value; + btv->opt_automute = c->val; break; case V4L2_CID_PRIVATE_AGC_CRUSH: - btv->opt_adc_crush = c->value; btwrite(BT848_ADC_RESERVED | - (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + (c->val ? BT848_ADC_CRUSH : 0), BT848_ADC); break; case V4L2_CID_PRIVATE_VCR_HACK: - btv->opt_vcr_hack = c->value; + btv->opt_vcr_hack = c->val; break; case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - btv->opt_whitecrush_upper = c->value; - btwrite(c->value, BT848_WC_UP); + btwrite(c->val, BT848_WC_UP); break; case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - btv->opt_whitecrush_lower = c->value; - btwrite(c->value, BT848_WC_DOWN); + btwrite(c->val, BT848_WC_DOWN); break; case V4L2_CID_PRIVATE_UV_RATIO: - btv->opt_uv_ratio = c->value; + btv->opt_uv_ratio = c->val; bt848_sat(btv, btv->saturation); break; case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - btv->opt_full_luma_range = c->value; - btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + btaor((c->val << 7), ~BT848_OFORM_RANGE, BT848_OFORM); break; case V4L2_CID_PRIVATE_CORING: - btv->opt_coring = c->value; - btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + btaor((c->val << 5), ~BT848_OFORM_CORE32, BT848_OFORM); break; default: return -EINVAL; @@ -1641,6 +1354,121 @@ static int bttv_s_ctrl(struct file *file, void *f, return 0; } +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_ctrl_ops bttv_ctrl_ops = { + .s_ctrl = bttv_s_ctrl, +}; + +static struct v4l2_ctrl_config bttv_ctrl_combfilter = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_COMBFILTER, + .name = "Comb Filter", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_automute = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_AUTOMUTE, + .name = "Auto Mute", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_lumafilter = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_LUMAFILTER, + .name = "Luma Decimation Filter", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_agc_crush = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_AGC_CRUSH, + .name = "AGC Crush", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_vcr_hack = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_VCR_HACK, + .name = "VCR Hack", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_whitecrush_lower = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, + .name = "Whitecrush Lower", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 255, + .step = 1, + .def = 0x7f, +}; + +static struct v4l2_ctrl_config bttv_ctrl_whitecrush_upper = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, + .name = "Whitecrush Upper", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 255, + .step = 1, + .def = 0xcf, +}; + +static struct v4l2_ctrl_config bttv_ctrl_uv_ratio = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_UV_RATIO, + .name = "UV Ratio", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 100, + .step = 1, + .def = 50, +}; + +static struct v4l2_ctrl_config bttv_ctrl_full_luma = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, + .name = "Full Luma Range", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_coring = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_CORING, + .name = "Coring", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 3, + .step = 1, +}; + + /* ----------------------------------------------------------------------- */ void bttv_gpio_tracking(struct bttv *btv, char *comment) @@ -2047,9 +1875,11 @@ static int bttv_s_frequency(struct file *file, void *priv, static int bttv_log_status(struct file *file, void *f) { + struct video_device *vdev = video_devdata(file); struct bttv_fh *fh = f; struct bttv *btv = fh->btv; + v4l2_ctrl_handler_log_status(vdev->ctrl_handler, btv->c.v4l2_dev.name); bttv_call_all(btv, core, log_status); return 0; } @@ -2939,30 +2769,6 @@ static int bttv_streamoff(struct file *file, void *priv, return 0; } -static int bttv_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - const struct v4l2_queryctrl *ctrl; - - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - - if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) - *c = no_ctl; - else { - ctrl = ctrl_by_id(c->id); - - *c = (NULL != ctrl) ? *ctrl : no_ctl; - } - - return 0; -} - static int bttv_g_parm(struct file *file, void *f, struct v4l2_streamparm *parm) { @@ -3263,6 +3069,7 @@ static int bttv_open(struct file *file) fh = kmalloc(sizeof(*fh), GFP_KERNEL); if (unlikely(!fh)) return -ENOMEM; + btv->users++; file->private_data = fh; *fh = btv->init; @@ -3287,7 +3094,6 @@ static int bttv_open(struct file *file) set_tvnorm(btv,btv->tvnorm); set_input(btv, btv->input, btv->tvnorm); - btv->users++; /* The V4L2 spec requires one global set of cropping parameters which only change on request. These are stored in btv->crop[1]. @@ -3349,7 +3155,7 @@ static int bttv_release(struct file *file) bttv_field_count(btv); if (!btv->users) - audio_mute(btv, 1); + audio_mute(btv, btv->mute); return 0; } @@ -3400,9 +3206,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_enum_input = bttv_enum_input, .vidioc_g_input = bttv_g_input, .vidioc_s_input = bttv_s_input, - .vidioc_queryctrl = bttv_queryctrl, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, .vidioc_streamon = bttv_streamon, .vidioc_streamoff = bttv_streamoff, .vidioc_g_tuner = bttv_g_tuner, @@ -3511,24 +3314,6 @@ static int radio_s_tuner(struct file *file, void *priv, return 0; } -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctl; - - return 0; -} - static ssize_t radio_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -3570,11 +3355,9 @@ static const struct v4l2_file_operations radio_fops = static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = bttv_querycap, + .vidioc_log_status = bttv_log_status, .vidioc_g_tuner = radio_g_tuner, .vidioc_s_tuner = radio_s_tuner, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, .vidioc_g_frequency = bttv_g_frequency, .vidioc_s_frequency = bttv_s_frequency, }; @@ -4220,6 +4003,7 @@ static int bttv_register_video(struct bttv *btv) btv->radio_dev = vdev_init(btv, &radio_template, "radio"); if (NULL == btv->radio_dev) goto err; + btv->radio_dev->ctrl_handler = &btv->radio_ctrl_handler; if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) goto err; @@ -4258,6 +4042,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) int result; unsigned char lat; struct bttv *btv; + struct v4l2_ctrl_handler *hdl; if (bttv_num == BTTV_MAX) return -ENOMEM; @@ -4317,6 +4102,10 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr); goto fail0; } + hdl = &btv->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 20); + btv->c.v4l2_dev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(&btv->radio_ctrl_handler, 6); btv->revision = dev->revision; pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); @@ -4353,16 +4142,19 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) /* init options from insmod args */ btv->opt_combfilter = combfilter; - btv->opt_lumafilter = lumafilter; + bttv_ctrl_combfilter.def = combfilter; + bttv_ctrl_lumafilter.def = lumafilter; btv->opt_automute = automute; - btv->opt_chroma_agc = chroma_agc; - btv->opt_adc_crush = adc_crush; + bttv_ctrl_automute.def = automute; + bttv_ctrl_agc_crush.def = agc_crush; btv->opt_vcr_hack = vcr_hack; - btv->opt_whitecrush_upper = whitecrush_upper; - btv->opt_whitecrush_lower = whitecrush_lower; + bttv_ctrl_vcr_hack.def = vcr_hack; + bttv_ctrl_whitecrush_upper.def = whitecrush_upper; + bttv_ctrl_whitecrush_lower.def = whitecrush_lower; btv->opt_uv_ratio = uv_ratio; - btv->opt_full_luma_range = full_luma_range; - btv->opt_coring = coring; + bttv_ctrl_uv_ratio.def = uv_ratio; + bttv_ctrl_full_luma.def = full_luma_range; + bttv_ctrl_coring.def = coring; /* fill struct bttv with some useful defaults */ btv->init.btv = btv; @@ -4373,6 +4165,34 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) btv->init.height = 240; btv->input = 0; + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 0xff00, 0x100, 32768); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_CONTRAST, 0, 0xff80, 0x80, 0x6c00); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_SATURATION, 0, 0xff80, 0x80, 32768); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_COLOR_KILLER, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_HUE, 0, 0xff00, 0x100, 32768); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_CHROMA_AGC, 0, 1, 1, !!chroma_agc); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + if (btv->volume_gpio) + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, 0xff00, 0x100, 0xff00); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_combfilter, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_automute, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_lumafilter, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_agc_crush, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_vcr_hack, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_whitecrush_lower, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_whitecrush_upper, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_uv_ratio, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_full_luma, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_coring, NULL); + /* initialize hardware */ if (bttv_gpio) bttv_gpio_tracking(btv,"pre-init"); @@ -4400,20 +4220,26 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) btv->radio_freq = 90500 * 16; /* 90.5Mhz default */ } init_irqreg(btv); + v4l2_ctrl_handler_setup(hdl); + if (hdl->error) { + result = hdl->error; + goto fail2; + } /* register video4linux + input */ if (!bttv_tvcards[btv->c.type].no_video) { - bttv_register_video(btv); - bt848_bright(btv,32768); - bt848_contrast(btv, 27648); - bt848_hue(btv,32768); - bt848_sat(btv,32768); - audio_mute(btv, 1); + v4l2_ctrl_add_handler(&btv->radio_ctrl_handler, hdl, + v4l2_ctrl_radio_filter); + if (btv->radio_ctrl_handler.error) { + result = btv->radio_ctrl_handler.error; + goto fail2; + } set_input(btv, 0, btv->tvnorm); bttv_crop_reset(&btv->crop[0], btv->tvnorm); btv->crop[1] = btv->crop[0]; /* current = default */ disclaim_vbi_lines(btv); disclaim_video_lines(btv); + bttv_register_video(btv); } /* add subdevices and autoload dvb-bt8xx if needed */ @@ -4435,6 +4261,8 @@ fail2: free_irq(btv->c.pci->irq,btv); fail1: + v4l2_ctrl_handler_free(&btv->ctrl_handler); + v4l2_ctrl_handler_free(&btv->radio_ctrl_handler); v4l2_device_unregister(&btv->c.v4l2_dev); fail0: @@ -4476,9 +4304,11 @@ static void bttv_remove(struct pci_dev *pci_dev) bttv_unregister_video(btv); /* free allocated memory */ + v4l2_ctrl_handler_free(&btv->ctrl_handler); + v4l2_ctrl_handler_free(&btv->radio_ctrl_handler); btcx_riscmem_free(btv->c.pci,&btv->main); - /* free ressources */ + /* free resources */ free_irq(btv->c.pci->irq,btv); iounmap(btv->bt848_mmio); release_mem_region(pci_resource_start(btv->c.pci,0), diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 528e03ec19e8..c3882ef3c529 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -33,9 +33,10 @@ #include #include #include +#include #include #include -#include +#include #include #include #include @@ -393,12 +394,17 @@ struct bttv { wait_queue_head_t i2c_queue; struct v4l2_subdev *sd_msp34xx; struct v4l2_subdev *sd_tvaudio; + struct v4l2_subdev *sd_tda7432; /* video4linux (1) */ struct video_device *video_dev; struct video_device *radio_dev; struct video_device *vbi_dev; + /* controls */ + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl_handler radio_ctrl_handler; + /* infrared remote */ int has_remote; struct bttv_ir *remote; @@ -426,17 +432,9 @@ struct bttv { /* various options */ int opt_combfilter; - int opt_lumafilter; int opt_automute; - int opt_chroma_agc; - int opt_color_killer; - int opt_adc_crush; int opt_vcr_hack; - int opt_whitecrush_upper; - int opt_whitecrush_lower; int opt_uv_ratio; - int opt_full_luma_range; - int opt_coring; /* radio data/state */ int has_radio; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index dcd63745e83a..1d00ca9f0ba3 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -146,6 +146,11 @@ enum v4l2_colorfx { * of controls. We reserve 16 controls for this driver. */ #define V4L2_CID_USER_MEYE_BASE (V4L2_CID_USER_BASE + 0x1000) +/* The base for the bttv driver controls. + * We reserve 32 controls for this driver. */ +#define V4L2_CID_USER_BTTV_BASE (V4L2_CID_USER_BASE + 0x1010) + + /* MPEG-class control IDs */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -- cgit v1.2.3 From 53bf0f446bc387eabdd535dca080789cc74607f4 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Fri, 25 Jan 2013 06:29:56 -0300 Subject: [media] v4l: Define video buffer flag for the COPY timestamp type Define video buffer flag for the COPY timestamp. In this case the timestamp value is copied from the OUTPUT to the corresponding CAPTURE buffer. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Reviewed-by: Sylwester Nawrocki Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/io.xml | 6 ++++++ include/uapi/linux/videodev2.h | 1 + 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index e6c58559ca6b..2c4c068dde83 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -1145,6 +1145,12 @@ in which case caches have not been used. same clock outside V4L2, use clock_gettime(2) . + + V4L2_BUF_FLAG_TIMESTAMP_COPY + 0x4000 + The CAPTURE buffer timestamp has been taken from the + corresponding OUTPUT buffer. This flag applies only to mem2mem devices. + diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 234d1d870914..b5f5cddcf1c3 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -705,6 +705,7 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_TIMESTAMP_MASK 0xe000 #define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN 0x0000 #define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000 +#define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x4000 /** * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor -- cgit v1.2.3 From 6aa69f99b2ecc7f9b387fcf22d30e6601b58819f Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Fri, 25 Jan 2013 06:29:57 -0300 Subject: [media] vb2: Add support for non monotonic timestamps Not all drivers use monotonic timestamps. This patch adds a way to set the timestamp type per every queue. In addition, set proper timestamp type in drivers that I am sure that use either MONOTONIC or COPY timestamps. Other drivers will correctly report UNKNOWN timestamp type instead of assuming that all drivers use monotonic timestamps. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Reviewed-by: Sylwester Nawrocki Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/blackfin/bfin_capture.c | 1 + drivers/media/platform/davinci/vpbe_display.c | 1 + drivers/media/platform/davinci/vpif_capture.c | 1 + drivers/media/platform/davinci/vpif_display.c | 1 + drivers/media/platform/s3c-camif/camif-capture.c | 1 + drivers/media/platform/s5p-fimc/fimc-capture.c | 1 + drivers/media/platform/s5p-fimc/fimc-lite.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 ++ drivers/media/platform/soc_camera/atmel-isi.c | 1 + drivers/media/platform/soc_camera/mx2_camera.c | 1 + drivers/media/platform/soc_camera/mx3_camera.c | 1 + drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | 1 + drivers/media/platform/vivi.c | 1 + drivers/media/usb/pwc/pwc-if.c | 1 + drivers/media/usb/stk1160/stk1160-v4l.c | 1 + drivers/media/usb/uvc/uvc_queue.c | 1 + drivers/media/v4l2-core/videobuf2-core.c | 8 ++++++-- include/media/videobuf2-core.h | 1 + 18 files changed, 24 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 5f209d5810dc..8ffe42aabd85 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -1029,6 +1029,7 @@ static int bcap_probe(struct platform_device *pdev) q->buf_struct_size = sizeof(struct bcap_buffer); q->ops = &bcap_video_qops; q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; vb2_queue_init(q); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 5e6b0cab514b..9f9f2c1a073f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1404,6 +1404,7 @@ static int vpbe_display_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpbe_disp_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 5892d2bc8eee..1943e41f3866 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1035,6 +1035,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_cap_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index dd249c96126d..5477c2cb8653 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1001,6 +1001,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_disp_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index a55793c3d811..e91f350929eb 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1153,6 +1153,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct camif_buffer); q->drv_priv = vp; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index f553cc2a8ee8..87b68420f771 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -1797,6 +1797,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, q->ops = &fimc_capture_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct fimc_vid_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index bfc4206935c8..47fbf7bcf608 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -1325,6 +1325,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct flite_buffer); q->drv_priv = fimc; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret < 0) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e84703c314ce..92c6bf11af74 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -804,6 +804,7 @@ static int s5p_mfc_open(struct file *file) goto err_queue_init; } q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { mfc_err("Failed to initialize videobuf2 queue(capture)\n"); @@ -825,6 +826,7 @@ static int s5p_mfc_open(struct file *file) goto err_queue_init; } q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { mfc_err("Failed to initialize videobuf2 queue(output)\n"); diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 82dbf99d347c..c314ff9b98dc 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -514,6 +514,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q, q->buf_struct_size = sizeof(struct frame_buffer); q->ops = &isi_video_qops; q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index ffba7d91f413..048c26a27c34 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -797,6 +797,7 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q, q->ops = &mx2_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mx2_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index f5cbb92db545..2c3bd69fb38c 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -455,6 +455,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q, q->ops = &mx3_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mx3_camera_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } 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 bb08a46432f4..973e72b24fa8 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -2026,6 +2026,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, q->ops = &sh_mobile_ceu_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index 8a33a712f480..c46d2e8677a5 100644 --- a/drivers/media/platform/vivi.c +++ b/drivers/media/platform/vivi.c @@ -1429,6 +1429,7 @@ static int __init vivi_create_instance(int inst) q->buf_struct_size = sizeof(struct vivi_buffer); q->ops = &vivi_video_qops; q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 5ec15cb1ed26..77bbf7889659 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -1001,6 +1001,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf); pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; + pdev->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(&pdev->vb_queue); if (rc < 0) { PWC_ERROR("Oops, could not initialize vb2 queue.\n"); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 6694f9e2ca57..5307a63e378f 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -687,6 +687,7 @@ int stk1160_vb2_setup(struct stk1160 *dev) q->buf_struct_size = sizeof(struct stk1160_buffer); q->ops = &stk1160_video_qops; q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(q); if (rc < 0) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 6c233a54ce40..cd962be860ca 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -149,6 +149,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; + queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&queue->queue); if (ret) return ret; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index db1235dcb328..be0448161c60 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -403,7 +403,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) * Clear any buffer state related flags. */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; - b->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + b->flags |= q->timestamp_type; switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -2039,9 +2039,13 @@ int vb2_queue_init(struct vb2_queue *q) WARN_ON(!q->type) || WARN_ON(!q->io_modes) || WARN_ON(!q->ops->queue_setup) || - WARN_ON(!q->ops->buf_queue)) + WARN_ON(!q->ops->buf_queue) || + WARN_ON(q->timestamp_type & ~V4L2_BUF_FLAG_TIMESTAMP_MASK)) return -EINVAL; + /* Warn that the driver should choose an appropriate timestamp type */ + WARN_ON(q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 9cfd4ee9e56f..a2d427450780 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -326,6 +326,7 @@ struct vb2_queue { const struct vb2_mem_ops *mem_ops; void *drv_priv; unsigned int buf_struct_size; + u32 timestamp_type; /* private: internal use only */ enum v4l2_memory memory; -- cgit v1.2.3 From 192f1e78cb9cbc1a2cee866f5e03a52857e648b6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 05:51:21 -0300 Subject: [media] s2255: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 172 ++++++++++++------------------------- include/uapi/linux/v4l2-controls.h | 4 + 2 files changed, 59 insertions(+), 117 deletions(-) (limited to 'include') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 498c57ea5d32..2dcb29b647f0 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -217,6 +218,7 @@ struct s2255_dev; struct s2255_channel { struct video_device vdev; + struct v4l2_ctrl_handler hdl; int resources; struct s2255_dmaqueue vidq; struct s2255_bufferi buffer; @@ -336,7 +338,7 @@ struct s2255_fh { */ #define S2255_V4L2_YC_ON 1 #define S2255_V4L2_YC_OFF 0 -#define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_S2255_COLORFILTER (V4L2_CID_USER_S2255_BASE + 0) /* frame prefix size (sent once every frame) */ #define PREFIX_SIZE 512 @@ -810,28 +812,6 @@ static void res_free(struct s2255_fh *fh) dprintk(1, "res: put\n"); } -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - static const char *colorfilter[] = { - "Off", - "On", - NULL - }; - if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) { - int i; - const char **menu_items = colorfilter; - for (i = 0; i < qmenu->index && menu_items[i]; i++) - ; /* do nothing (from v4l2-common.c) */ - if (menu_items[i] == NULL || menu_items[i][0] == '\0') - return -EINVAL; - strlcpy(qmenu->name, menu_items[qmenu->index], - sizeof(qmenu->name)); - return 0; - } - return v4l2_ctrl_query_menu(qmenu, NULL, NULL); -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1427,109 +1407,32 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -/* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - struct s2255_dev *dev = fh->dev; - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT); - break; - case V4L2_CID_CONTRAST: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST); - break; - case V4L2_CID_SATURATION: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION); - break; - case V4L2_CID_HUE: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE); - break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; - strlcpy(qc->name, "Color Filter", sizeof(qc->name)); - qc->type = V4L2_CTRL_TYPE_MENU; - qc->minimum = 0; - qc->maximum = 1; - qc->step = 1; - qc->default_value = 1; - qc->flags = 0; - break; - default: - return -EINVAL; - } - dprintk(4, "%s, id %d\n", __func__, qc->id); - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct s2255_fh *fh = priv; - struct s2255_dev *dev = fh->dev; - struct s2255_channel *channel = fh->channel; - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = channel->mode.bright; - break; - case V4L2_CID_CONTRAST: - ctrl->value = channel->mode.contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = channel->mode.saturation; - break; - case V4L2_CID_HUE: - ctrl->value = channel->mode.hue; - break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; - ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16); - break; - default: - return -EINVAL; - } - dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value); - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); + struct s2255_channel *channel = + container_of(ctrl->handler, struct s2255_channel, hdl); struct s2255_mode mode; + mode = channel->mode; dprintk(4, "%s\n", __func__); + /* update the mode to the corresponding value */ switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - mode.bright = ctrl->value; + mode.bright = ctrl->val; break; case V4L2_CID_CONTRAST: - mode.contrast = ctrl->value; + mode.contrast = ctrl->val; break; case V4L2_CID_HUE: - mode.hue = ctrl->value; + mode.hue = ctrl->val; break; case V4L2_CID_SATURATION: - mode.saturation = ctrl->value; + mode.saturation = ctrl->val; break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; + case V4L2_CID_S2255_COLORFILTER: mode.color &= ~MASK_INPUT_TYPE; - mode.color |= ((ctrl->value ? 0 : 1) << 16); + mode.color |= !ctrl->val << 16; break; default: return -EINVAL; @@ -1539,7 +1442,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, some V4L programs restart stream unnecessarily after a s_crtl. */ - s2255_set_mode(fh->channel, &mode); + s2255_set_mode(channel, &mode); return 0; } @@ -1886,7 +1789,6 @@ static const struct v4l2_file_operations s2255_fops_v4l = { }; static const struct v4l2_ioctl_ops s2255_ioctl_ops = { - .vidioc_querymenu = vidioc_querymenu, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1900,9 +1802,6 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_s_jpegcomp = vidioc_s_jpegcomp, @@ -1915,8 +1814,13 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { static void s2255_video_device_release(struct video_device *vdev) { struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); - dprintk(4, "%s, chnls: %d \n", __func__, + struct s2255_channel *channel = + container_of(vdev, struct s2255_channel, vdev); + + v4l2_ctrl_handler_free(&channel->hdl); + dprintk(4, "%s, chnls: %d\n", __func__, atomic_read(&dev->num_channels)); + if (atomic_dec_and_test(&dev->num_channels)) s2255_destroy(dev); return; @@ -1931,6 +1835,20 @@ static struct video_device template = { .current_norm = V4L2_STD_NTSC_M, }; +static const struct v4l2_ctrl_ops s2255_ctrl_ops = { + .s_ctrl = s2255_s_ctrl, +}; + +static const struct v4l2_ctrl_config color_filter_ctrl = { + .ops = &s2255_ctrl_ops, + .name = "Color Filter", + .id = V4L2_CID_S2255_COLORFILTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, + .def = 1, +}; + static int s2255_probe_v4l(struct s2255_dev *dev) { int ret; @@ -1945,9 +1863,29 @@ static int s2255_probe_v4l(struct s2255_dev *dev) for (i = 0; i < MAX_CHANNELS; i++) { channel = &dev->channel[i]; INIT_LIST_HEAD(&channel->vidq.active); + + v4l2_ctrl_handler_init(&channel->hdl, 5); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_HUE, 0, 255, 1, DEF_HUE); + if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && + (dev->pid != 0x2257 || channel->idx <= 1)) + v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL); + if (channel->hdl.error) { + ret = channel->hdl.error; + v4l2_ctrl_handler_free(&channel->hdl); + dev_err(&dev->udev->dev, "couldn't register control\n"); + break; + } channel->vidq.dev = dev; /* register 4 video devices */ channel->vdev = template; + channel->vdev.ctrl_handler = &channel->hdl; channel->vdev.lock = &dev->lock; channel->vdev.v4l2_dev = &dev->v4l2_dev; video_set_drvdata(&channel->vdev, channel); diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 1d00ca9f0ba3..7eab0b91827b 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -151,6 +151,10 @@ enum v4l2_colorfx { #define V4L2_CID_USER_BTTV_BASE (V4L2_CID_USER_BASE + 0x1010) +/* The base for the s2255 driver controls. + * We reserve 8 controls for this driver. */ +#define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1010) + /* MPEG-class control IDs */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -- cgit v1.2.3 From c6c1d50b51e76b57fbf0651d38a7ae0c3fb9d5cc Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 22 Jan 2013 12:27:55 -0300 Subject: [media] media: Add 64--32 bit compat ioctl handler Provide an ioctl handler for 32-bit binaries on 64-bit systems. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-devnode.c | 31 ++++++++++++++++++++++++++++--- include/media/media-devnode.h | 1 + 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 023b2a1cbb9b..fb0f0469fad7 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -116,19 +116,41 @@ static unsigned int media_poll(struct file *filp, return mdev->fops->poll(filp, poll); } -static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static long +__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, + long (*ioctl_func)(struct file *filp, unsigned int cmd, + unsigned long arg)) { struct media_devnode *mdev = media_devnode_data(filp); - if (!mdev->fops->ioctl) + if (!ioctl_func) return -ENOTTY; if (!media_devnode_is_registered(mdev)) return -EIO; - return mdev->fops->ioctl(filp, cmd, arg); + return ioctl_func(filp, cmd, arg); +} + +static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl); } +#ifdef CONFIG_COMPAT + +static long media_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl); +} + +#endif /* CONFIG_COMPAT */ + /* Override for the open function */ static int media_open(struct inode *inode, struct file *filp) { @@ -188,6 +210,9 @@ static const struct file_operations media_devnode_fops = { .write = media_write, .open = media_open, .unlocked_ioctl = media_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = media_compat_ioctl, +#endif /* CONFIG_COMPAT */ .release = media_release, .poll = media_poll, .llseek = no_llseek, diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index f6caafc874cb..3446af279fca 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -46,6 +46,7 @@ struct media_file_operations { ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*ioctl) (struct file *, unsigned int, unsigned long); + long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*open) (struct file *); int (*release) (struct file *); }; -- cgit v1.2.3 From ef2d41b19b8100ce63eabba9ee87953aa685921a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:06:28 -0300 Subject: [media] davinci: remove VPBE_ENC_DV_PRESET and rename VPBE_ENC_CUSTOM_TIMINGS Remove VPBE_ENC_DV_PRESET (the DV_PRESET API is no longer supported) and VPBE_ENC_CUSTOM_TIMINGS is renamed to VPBE_ENC_DV_TIMINGS since the old "CUSTOM_TIMINGS" name is deprecated in favor of "DV_TIMINGS". Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-davinci/board-dm644x-evm.c | 4 ++-- arch/arm/mach-davinci/dm644x.c | 2 +- drivers/media/platform/davinci/vpbe.c | 8 ++++---- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpbe_venc.c | 8 ++++---- include/media/davinci/vpbe_types.h | 3 +-- 6 files changed, 13 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 71735e7797cc..a02180052a76 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -649,7 +649,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { { .name = "480p59_94", - .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .timings_type = VPBE_ENC_DV_TIMINGS, .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, .interlaced = 0, .xres = 720, @@ -661,7 +661,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { }, { .name = "576p50", - .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .timings_type = VPBE_ENC_DV_TIMINGS, .dv_timings = V4L2_DV_BT_CEA_720X576P50, .interlaced = 0, .xres = 720, diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index db1dd92e00af..ee0e994748e0 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -706,7 +706,7 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); break; - case VPBE_ENC_CUSTOM_TIMINGS: + case VPBE_ENC_DV_TIMINGS: if (pclock <= 27000000) { v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 4ca0f9a2ad8a..2a49f00c4543 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -344,7 +344,7 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, return -EINVAL; for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS && + if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS && !memcmp(&output->modes[i].dv_timings, dv_timings, sizeof(*dv_timings))) break; @@ -385,7 +385,7 @@ static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, struct v4l2_dv_timings *dv_timings) { if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_CUSTOM_TIMINGS) { + VPBE_ENC_DV_TIMINGS) { *dv_timings = vpbe_dev->current_timings.dv_timings; return 0; } @@ -412,7 +412,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, return -EINVAL; for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS) { + if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS) { if (j == timings->index) break; j++; @@ -515,7 +515,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, return vpbe_s_std(vpbe_dev, &preset_mode->std_id); if (preset_mode->timings_type & - VPBE_ENC_CUSTOM_TIMINGS) { + VPBE_ENC_DV_TIMINGS) { dv_timings = preset_mode->dv_timings; return vpbe_s_dv_timings(vpbe_dev, &dv_timings); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 9f9f2c1a073f..8290fddbd47d 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1202,7 +1202,7 @@ vpbe_display_g_dv_timings(struct file *file, void *priv, /* Get the given standard in the encoder */ if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_CUSTOM_TIMINGS) { + VPBE_ENC_DV_TIMINGS) { *dv_timings = vpbe_dev->current_timings.dv_timings; } else { return -EINVAL; diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index bdbebd59df98..9546d268e2db 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -313,7 +313,7 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -360,7 +360,7 @@ static int venc_set_576p50(struct v4l2_subdev *sd) venc->venc_type != VPBE_VERSION_2) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -400,7 +400,7 @@ static int venc_set_720p60_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -428,7 +428,7 @@ static int venc_set_1080i30_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h index 9b85396514be..05dbe0ba514c 100644 --- a/include/media/davinci/vpbe_types.h +++ b/include/media/davinci/vpbe_types.h @@ -26,8 +26,7 @@ enum vpbe_version { /* vpbe_timing_type - Timing types used in vpbe device */ enum vpbe_enc_timings_type { VPBE_ENC_STD = 0x1, - VPBE_ENC_DV_PRESET = 0x2, - VPBE_ENC_CUSTOM_TIMINGS = 0x4, + VPBE_ENC_DV_TIMINGS = 0x4, /* Used when set timings through FB device interface */ VPBE_ENC_TIMINGS_INVALID = 0x8, }; -- cgit v1.2.3 From 1de1951930d4450d1645a0a907b710f268af42c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 07:18:38 -0300 Subject: [media] davinci/dm644x_ccdc: fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/platform/davinci/dm644x_ccdc.c: In function ‘validate_ccdc_param’: drivers/media/platform/davinci/dm644x_ccdc.c:233:32: warning: comparison between ‘enum ccdc_gama_width’ and ‘enum ccdc_data_size’ [-Wenum-compare] It took a bit of work, see this thread of an earlier attempt to fix this: https://patchwork.kernel.org/patch/1923091/ I've chosen not to follow the suggestions in that thread since gamma_width is really a different property from data_size. What you really want is to know if gamma_width fits inside data_size and for that you need to translate each enum into a maximum bit number so you can safely compare the two. So I put in two static inline translation functions instead, keeping the rest of the code the same (except for fixing the 'gama' typo). Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm644x_ccdc.c | 13 +++++++----- drivers/media/platform/davinci/dm644x_ccdc_regs.h | 2 +- include/media/davinci/dm644x_ccdc.h | 24 +++++++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 318e80512998..971d639b6674 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -228,9 +228,12 @@ static void ccdc_readregs(void) static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) { if (ccdcparam->alaw.enable) { - if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || - (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || - (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { + u8 max_gamma = ccdc_gamma_width_max_bit(ccdcparam->alaw.gamma_wd); + u8 max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); + + if ((ccdcparam->alaw.gamma_wd > CCDC_GAMMA_BITS_09_0) || + (ccdcparam->alaw.gamma_wd < CCDC_GAMMA_BITS_15_6) || + (max_gamma > max_data)) { dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); return -1; } @@ -560,8 +563,8 @@ void ccdc_config_raw(void) /* Enable and configure aLaw register if needed */ if (config_params->alaw.enable) { - val = ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); + val = ((config_params->alaw.gamma_wd & + CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE); regw(val, CCDC_ALAW); dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); } diff --git a/drivers/media/platform/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h index 90370e414e2c..2b0aca5383f0 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc_regs.h +++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h @@ -84,7 +84,7 @@ #define CCDC_VDHDEN_ENABLE (1 << 16) #define CCDC_LPF_ENABLE (1 << 14) #define CCDC_ALAW_ENABLE (1 << 3) -#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_ALAW_GAMMA_WD_MASK 7 #define CCDC_BLK_CLAMP_ENABLE (1 << 31) #define CCDC_BLK_SGAIN_MASK 0x1F #define CCDC_BLK_ST_PXL_MASK 0x7FFF diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h index 3e178eb52fb3..852e96c4bb46 100644 --- a/include/media/davinci/dm644x_ccdc.h +++ b/include/media/davinci/dm644x_ccdc.h @@ -38,17 +38,23 @@ enum ccdc_sample_line { CCDC_SAMPLE_16LINES }; -/* enum for Alaw gama width */ -enum ccdc_gama_width { - CCDC_GAMMA_BITS_15_6, +/* enum for Alaw gamma width */ +enum ccdc_gamma_width { + CCDC_GAMMA_BITS_15_6, /* use bits 15-6 for gamma */ CCDC_GAMMA_BITS_14_5, CCDC_GAMMA_BITS_13_4, CCDC_GAMMA_BITS_12_3, CCDC_GAMMA_BITS_11_2, CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 + CCDC_GAMMA_BITS_09_0 /* use bits 9-0 for gamma */ }; +/* returns the highest bit used for the gamma */ +static inline u8 ccdc_gamma_width_max_bit(enum ccdc_gamma_width width) +{ + return 15 - width; +} + enum ccdc_data_size { CCDC_DATA_16BITS, CCDC_DATA_15BITS, @@ -60,12 +66,18 @@ enum ccdc_data_size { CCDC_DATA_8BITS }; +/* returns the highest bit used for this data size */ +static inline u8 ccdc_data_size_max_bit(enum ccdc_data_size sz) +{ + return sz == CCDC_DATA_8BITS ? 7 : 15 - sz; +} + /* structure for ALaw */ struct ccdc_a_law { /* Enable/disable A-Law */ unsigned char enable; - /* Gama Width Input */ - enum ccdc_gama_width gama_wd; + /* Gamma Width Input */ + enum ccdc_gamma_width gamma_wd; }; /* structure for Black Clamping */ -- cgit v1.2.3 From db242f62bd18f6c689c0e04f3df14be2deb89462 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 07:24:07 -0300 Subject: [media] davinci: more gama -> gamma typo fixes Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm355_ccdc.c | 10 +++++----- drivers/media/platform/davinci/dm355_ccdc_regs.h | 2 +- drivers/media/platform/davinci/isif.c | 2 +- drivers/media/platform/davinci/isif_regs.h | 4 ++-- include/media/davinci/dm355_ccdc.h | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 4277e4ad810c..2364dbab8046 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -85,7 +85,7 @@ static struct ccdc_oper_config { .mfilt1 = CCDC_NO_MEDIAN_FILTER1, .mfilt2 = CCDC_NO_MEDIAN_FILTER2, .alaw = { - .gama_wd = 2, + .gamma_wd = 2, }, .blk_clamp = { .sample_pixel = 1, @@ -303,8 +303,8 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) } if (ccdcparam->alaw.enable) { - if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || - ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { + if (ccdcparam->alaw.gamma_wd < CCDC_GAMMA_BITS_13_4 || + ccdcparam->alaw.gamma_wd > CCDC_GAMMA_BITS_09_0) { dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); return -EINVAL; } @@ -680,8 +680,8 @@ static int ccdc_config_raw(void) /* Enable and configure aLaw register if needed */ if (config_params->alaw.enable) { val |= (CCDC_ALAW_ENABLE | - ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) << + ((config_params->alaw.gamma_wd & + CCDC_ALAW_GAMMA_WD_MASK) << CCDC_GAMMAWD_INPUT_SHIFT)); } diff --git a/drivers/media/platform/davinci/dm355_ccdc_regs.h b/drivers/media/platform/davinci/dm355_ccdc_regs.h index d6d2ef0533b5..2e1946e0b99f 100644 --- a/drivers/media/platform/davinci/dm355_ccdc_regs.h +++ b/drivers/media/platform/davinci/dm355_ccdc_regs.h @@ -153,7 +153,7 @@ #define CCDC_VDHDEN_ENABLE (1 << 16) #define CCDC_LPF_ENABLE (1 << 14) #define CCDC_ALAW_ENABLE 1 -#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_ALAW_GAMMA_WD_MASK 7 #define CCDC_REC656IF_BT656_EN 3 #define CCDC_FMTCFG_FMTMODE_MASK 3 diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 5050f9265f48..abc3ae36645c 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -604,7 +604,7 @@ static int isif_config_raw(void) if (module_params->compress.alg == ISIF_ALAW) val |= ISIF_ALAW_ENABLE; - val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); + val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT); regw(val, CGAMMAWD); /* Configure DPCM compression settings */ diff --git a/drivers/media/platform/davinci/isif_regs.h b/drivers/media/platform/davinci/isif_regs.h index aa69a463c122..3993aece821b 100644 --- a/drivers/media/platform/davinci/isif_regs.h +++ b/drivers/media/platform/davinci/isif_regs.h @@ -203,8 +203,8 @@ #define ISIF_LPF_MASK 1 /* GAMMAWD registers */ -#define ISIF_ALAW_GAMA_WD_MASK 0xF -#define ISIF_ALAW_GAMA_WD_SHIFT 1 +#define ISIF_ALAW_GAMMA_WD_MASK 0xF +#define ISIF_ALAW_GAMMA_WD_SHIFT 1 #define ISIF_ALAW_ENABLE 1 #define ISIF_GAMMAWD_CFA_SHIFT 5 diff --git a/include/media/davinci/dm355_ccdc.h b/include/media/davinci/dm355_ccdc.h index adf2fe4bf0bb..c669a9fb75e5 100644 --- a/include/media/davinci/dm355_ccdc.h +++ b/include/media/davinci/dm355_ccdc.h @@ -38,7 +38,7 @@ enum ccdc_sample_line { CCDC_SAMPLE_16LINES }; -/* enum for Alaw gama width */ +/* enum for Alaw gamma width */ enum ccdc_gamma_width { CCDC_GAMMA_BITS_13_4, CCDC_GAMMA_BITS_12_3, @@ -97,8 +97,8 @@ enum ccdc_mfilt2 { struct ccdc_a_law { /* Enable/disable A-Law */ unsigned char enable; - /* Gama Width Input */ - enum ccdc_gamma_width gama_wd; + /* Gamma Width Input */ + enum ccdc_gamma_width gamma_wd; }; /* structure for Black Clamping */ -- cgit v1.2.3 From b6ba2057f7823352bbc44ee846faa03b36e8b6ac Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 1 Mar 2013 15:44:20 -0300 Subject: [media] videobuf2: add gfp_flags Some drivers have special memory requirements for their buffers, usually related to DMA (e.g. GFP_DMA or __GFP_DMA32). Make it possible to specify additional GFP flags for those buffers by adding a gfp_flags field to vb2_queue. Note that this field will be replaced in the future with a different mechanism, but that is still work in progress and we need this feature now so we won't be able to convert drivers with such requirements to vb2. Signed-off-by: Hans Verkuil Acked-by: Marek Szyprowski Acked-by: Federico Vaga Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 2 +- drivers/media/v4l2-core/videobuf2-dma-contig.c | 5 +++-- drivers/media/v4l2-core/videobuf2-dma-sg.c | 5 +++-- drivers/media/v4l2-core/videobuf2-vmalloc.c | 4 ++-- include/media/videobuf2-core.h | 10 ++++++++-- 5 files changed, 17 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index be0448161c60..70827feb87b4 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -57,7 +57,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) /* Allocate memory for all planes in this buffer */ for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], - q->plane_sizes[plane]); + q->plane_sizes[plane], q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 10beaee7f0ae..ae35d255a430 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -152,7 +152,7 @@ static void vb2_dc_put(void *buf_priv) kfree(buf); } -static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size) +static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) { struct vb2_dc_conf *conf = alloc_ctx; struct device *dev = conf->dev; @@ -165,7 +165,8 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size) /* align image size to PAGE_SIZE */ size = PAGE_ALIGN(size); - buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, GFP_KERNEL); + buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, + GFP_KERNEL | gfp_flags); if (!buf->vaddr) { dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size); kfree(buf); diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 25c3b360e1ad..952776fafe2c 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -33,7 +33,7 @@ struct vb2_dma_sg_buf { static void vb2_dma_sg_put(void *buf_priv); -static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) +static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) { struct vb2_dma_sg_buf *buf; int i; @@ -60,7 +60,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) goto fail_pages_array_alloc; for (i = 0; i < buf->sg_desc.num_pages; ++i) { - buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN); + buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | + __GFP_NOWARN | gfp_flags); if (NULL == buf->pages[i]) goto fail_pages_alloc; sg_set_page(&buf->sg_desc.sglist[i], diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index a47fd4f589a1..313d9771b2bc 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -35,11 +35,11 @@ struct vb2_vmalloc_buf { static void vb2_vmalloc_put(void *buf_priv); -static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) +static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) { struct vb2_vmalloc_buf *buf; - buf = kzalloc(sizeof(*buf), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags); if (!buf) return NULL; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index a2d427450780..d88a098d1aff 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -27,7 +27,9 @@ struct vb2_fileio_data; * return NULL on failure or a pointer to allocator private, * per-buffer data on success; the returned private structure * will then be passed as buf_priv argument to other ops in this - * structure + * structure. Additional gfp_flags to use when allocating the + * are also passed to this operation. These flags are from the + * gfp_flags field of vb2_queue. * @put: inform the allocator that the buffer will no longer be used; * usually will result in the allocator freeing the buffer (if * no other users of this buffer are present); the buf_priv @@ -79,7 +81,7 @@ struct vb2_fileio_data; * unmap_dmabuf. */ struct vb2_mem_ops { - void *(*alloc)(void *alloc_ctx, unsigned long size); + void *(*alloc)(void *alloc_ctx, unsigned long size, gfp_t gfp_flags); void (*put)(void *buf_priv); struct dma_buf *(*get_dmabuf)(void *buf_priv); @@ -302,6 +304,9 @@ struct v4l2_fh; * @buf_struct_size: size of the driver-specific buffer structure; * "0" indicates the driver doesn't want to use a custom buffer * structure type, so sizeof(struct vb2_buffer) will is used + * @gfp_flags: additional gfp flags used when allocating the buffers. + * Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32 + * to force the buffer allocation to a specific memory zone. * * @memory: current memory type used * @bufs: videobuf buffer structures @@ -327,6 +332,7 @@ struct vb2_queue { void *drv_priv; unsigned int buf_struct_size; u32 timestamp_type; + gfp_t gfp_flags; /* private: internal use only */ enum v4l2_memory memory; -- cgit v1.2.3 From 88da0183eb2b72048099b4e0ecae1705f5309c94 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Mon, 18 Feb 2013 07:56:41 -0300 Subject: [media] media: ths7353: add support for ths7353 video amplifier The patch adds support for THS7353 video amplifier. The the THS7353 amplifier is very much similar to the existing THS7303 video amplifier driver. This patch appropriately makes changes to the existing ths7303 driver and adds support for the THS7353. This patch also adds V4L2_IDENT_THS7353 for the THS7353 chip and appropriate changes to Kconfig file for building. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Martin Bugge Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 6 +- drivers/media/i2c/ths7303.c | 351 +++++++++++++++++++++++++++++++++------- include/media/ths7303.h | 42 +++++ include/media/v4l2-chip-ident.h | 3 + 4 files changed, 340 insertions(+), 62 deletions(-) create mode 100644 include/media/ths7303.h (limited to 'include') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 7b771baa2212..ec07ceb41c9c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -550,10 +550,10 @@ config VIDEO_UPD64083 comment "Miscelaneous helper chips" config VIDEO_THS7303 - tristate "THS7303 Video Amplifier" - depends on I2C + tristate "THS7303/53 Video Amplifier" + depends on VIDEO_V4L2 && I2C help - Support for TI THS7303 video amplifier + Support for TI THS7303/53 video amplifier To compile this driver as a module, choose M here: the module will be called ths7303. diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index e747524ba6ed..3ca60c7cd95f 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -1,7 +1,15 @@ /* - * ths7303- THS7303 Video Amplifier driver + * ths7303/53- THS7303/53 Video Amplifier driver * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. + * + * Author: Chaithrika U S + * + * Contributors: + * Hans Verkuil + * Lad, Prabhakar + * Martin Bugge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,25 +21,27 @@ * GNU General Public License for more details. */ -#include -#include -#include -#include #include -#include -#include #include -#include -#include +#include -#include -#include +#include #include +#include #define THS7303_CHANNEL_1 1 #define THS7303_CHANNEL_2 2 #define THS7303_CHANNEL_3 3 +struct ths7303_state { + struct v4l2_subdev sd; + struct ths7303_platform_data pdata; + struct v4l2_bt_timings bt; + int std_id; + int stream_on; + int driver_data; +}; + enum ths7303_filter_mode { THS7303_FILTER_MODE_480I_576I, THS7303_FILTER_MODE_480P_576P, @@ -48,64 +58,84 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level 0-1"); +static inline struct ths7303_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ths7303_state, sd); +} + +static int ths7303_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int ths7303_write(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = i2c_smbus_write_byte_data(client, reg, val); + if (ret == 0) + return 0; + } + return ret; +} + /* following function is used to set ths7303 */ int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode) { - u8 input_bias_chroma = 3; - u8 input_bias_luma = 3; - int disable = 0; - int err = 0; - u8 val = 0; - u8 temp; - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ths7303_state *state = to_state(sd); + struct ths7303_platform_data *pdata = &state->pdata; + u8 val, sel = 0; + int err, disable = 0; if (!client) return -EINVAL; switch (mode) { case THS7303_FILTER_MODE_1080P: - val = (3 << 6); - val |= (3 << 3); + sel = 0x3; /*1080p and SXGA/UXGA */ break; case THS7303_FILTER_MODE_720P_1080I: - val = (2 << 6); - val |= (2 << 3); + sel = 0x2; /*720p, 1080i and SVGA/XGA */ break; case THS7303_FILTER_MODE_480P_576P: - val = (1 << 6); - val |= (1 << 3); + sel = 0x1; /* EDTV 480p/576p and VGA */ break; case THS7303_FILTER_MODE_480I_576I: + sel = 0x0; /* SDTV, S-Video, 480i/576i */ break; - case THS7303_FILTER_MODE_DISABLE: - pr_info("mode disabled\n"); - /* disable all channels */ - disable = 1; default: /* disable all channels */ disable = 1; } - /* Setup channel 2 - Luma - Green */ - temp = val; + + val = (sel << 6) | (sel << 3); if (!disable) - val |= input_bias_luma; - err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_2, val); + val |= (pdata->ch_1 & 0x27); + err = ths7303_write(sd, THS7303_CHANNEL_1, val); if (err) goto out; - /* setup two chroma channels */ + val = (sel << 6) | (sel << 3); if (!disable) - temp |= input_bias_chroma; - - err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_1, temp); + val |= (pdata->ch_2 & 0x27); + err = ths7303_write(sd, THS7303_CHANNEL_2, val); if (err) goto out; - err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_3, temp); + val = (sel << 6) | (sel << 3); + if (!disable) + val |= (pdata->ch_3 & 0x27); + err = ths7303_write(sd, THS7303_CHANNEL_3, val); if (err) goto out; - return err; + + return 0; out: pr_info("write byte data failed\n"); return err; @@ -113,49 +143,209 @@ out: static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) { - if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) + struct ths7303_state *state = to_state(sd); + + if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { + state->std_id = 1; + state->bt.pixelclock = 0; return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I); - else - return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); + } + + return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); } -/* for setting filter for HD output */ -static int ths7303_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *dv_timings) +static int ths7303_config(struct v4l2_subdev *sd) { - u32 height = dv_timings->bt.height; - int interlaced = dv_timings->bt.interlaced; - int res = 0; + struct ths7303_state *state = to_state(sd); + int res; + + if (!state->stream_on) { + ths7303_write(sd, THS7303_CHANNEL_1, + (ths7303_read(sd, THS7303_CHANNEL_1) & 0xf8) | + 0x00); + ths7303_write(sd, THS7303_CHANNEL_2, + (ths7303_read(sd, THS7303_CHANNEL_2) & 0xf8) | + 0x00); + ths7303_write(sd, THS7303_CHANNEL_3, + (ths7303_read(sd, THS7303_CHANNEL_3) & 0xf8) | + 0x00); + return 0; + } - if (height == 1080 && !interlaced) + if (state->bt.pixelclock > 120000000) res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P); - else if ((height == 720 && !interlaced) || - (height == 1080 && interlaced)) + else if (state->bt.pixelclock > 70000000) res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I); - else if ((height == 480 || height == 576) && !interlaced) + else if (state->bt.pixelclock > 20000000) res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P); + else if (state->std_id) + res = ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I); else /* disable all channels */ res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); return res; + +} + +static int ths7303_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ths7303_state *state = to_state(sd); + + state->stream_on = enable; + + return ths7303_config(sd); +} + +/* for setting filter for HD output */ +static int ths7303_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) +{ + struct ths7303_state *state = to_state(sd); + + if (!dv_timings || dv_timings->type != V4L2_DV_BT_656_1120) + return -EINVAL; + + state->bt = dv_timings->bt; + state->std_id = 0; + + return ths7303_config(sd); } static int ths7303_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ths7303_state *state = to_state(sd); - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0); + return v4l2_chip_ident_i2c_client(client, chip, state->driver_data, 0); } static const struct v4l2_subdev_video_ops ths7303_video_ops = { + .s_stream = ths7303_s_stream, .s_std_output = ths7303_s_std_output, - .s_dv_timings = ths7303_s_dv_timings, + .s_dv_timings = ths7303_s_dv_timings, }; +#ifdef CONFIG_VIDEO_ADV_DEBUG + +static int ths7303_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + reg->size = 1; + reg->val = ths7303_read(sd, reg->reg); + return 0; +} + +static int ths7303_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ths7303_write(sd, reg->reg, reg->val); + return 0; +} +#endif + +static const char * const stc_lpf_sel_txt[4] = { + "500-kHz Filter", + "2.5-MHz Filter", + "5-MHz Filter", + "5-MHz Filter", +}; + +static const char * const in_mux_sel_txt[2] = { + "Input A Select", + "Input B Select", +}; + +static const char * const lpf_freq_sel_txt[4] = { + "9-MHz LPF", + "16-MHz LPF", + "35-MHz LPF", + "Bypass LPF", +}; + +static const char * const in_bias_sel_dis_cont_txt[8] = { + "Disable Channel", + "Mute Function - No Output", + "DC Bias Select", + "DC Bias + 250 mV Offset Select", + "AC Bias Select", + "Sync Tip Clamp with low bias", + "Sync Tip Clamp with mid bias", + "Sync Tip Clamp with high bias", +}; + +static void ths7303_log_channel_status(struct v4l2_subdev *sd, u8 reg) +{ + u8 val = ths7303_read(sd, reg); + + if ((val & 0x7) == 0) { + v4l2_info(sd, "Channel %d Off\n", reg); + return; + } + + v4l2_info(sd, "Channel %d On\n", reg); + v4l2_info(sd, " value 0x%x\n", val); + v4l2_info(sd, " %s\n", stc_lpf_sel_txt[(val >> 6) & 0x3]); + v4l2_info(sd, " %s\n", in_mux_sel_txt[(val >> 5) & 0x1]); + v4l2_info(sd, " %s\n", lpf_freq_sel_txt[(val >> 3) & 0x3]); + v4l2_info(sd, " %s\n", in_bias_sel_dis_cont_txt[(val >> 0) & 0x7]); +} + +static int ths7303_log_status(struct v4l2_subdev *sd) +{ + struct ths7303_state *state = to_state(sd); + + v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off"); + + if (state->bt.pixelclock) { + struct v4l2_bt_timings *bt = bt = &state->bt; + u32 frame_width, frame_height; + + frame_width = bt->width + bt->hfrontporch + + bt->hsync + bt->hbackporch; + frame_height = bt->height + bt->vfrontporch + + bt->vsync + bt->vbackporch; + v4l2_info(sd, + "timings: %dx%d%s%d (%dx%d). Pix freq. = %d Hz. Polarities = 0x%x\n", + bt->width, bt->height, bt->interlaced ? "i" : "p", + (frame_height * frame_width) > 0 ? + (int)bt->pixelclock / + (frame_height * frame_width) : 0, + frame_width, frame_height, + (int)bt->pixelclock, bt->polarities); + } else { + v4l2_info(sd, "no timings set\n"); + } + + ths7303_log_channel_status(sd, THS7303_CHANNEL_1); + ths7303_log_channel_status(sd, THS7303_CHANNEL_2); + ths7303_log_channel_status(sd, THS7303_CHANNEL_3); + + return 0; +} + static const struct v4l2_subdev_core_ops ths7303_core_ops = { .g_chip_ident = ths7303_g_chip_ident, + .log_status = ths7303_log_status, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ths7303_g_register, + .s_register = ths7303_s_register, +#endif }; static const struct v4l2_subdev_ops ths7303_ops = { @@ -163,11 +353,38 @@ static const struct v4l2_subdev_ops ths7303_ops = { .video = &ths7303_video_ops, }; +static int ths7303_setup(struct v4l2_subdev *sd) +{ + struct ths7303_state *state = to_state(sd); + struct ths7303_platform_data *pdata = &state->pdata; + int ret; + u8 mask; + + state->stream_on = pdata->init_enable; + + mask = state->stream_on ? 0xff : 0xf8; + + ret = ths7303_write(sd, THS7303_CHANNEL_1, pdata->ch_1 & mask); + if (ret) + return ret; + + ret = ths7303_write(sd, THS7303_CHANNEL_2, pdata->ch_2 & mask); + if (ret) + return ret; + + ret = ths7303_write(sd, THS7303_CHANNEL_3, pdata->ch_3 & mask); + if (ret) + return ret; + + return 0; +} + static int ths7303_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct ths7303_platform_data *pdata = client->dev.platform_data; + struct ths7303_state *state; struct v4l2_subdev *sd; - v4l2_std_id std_id = V4L2_STD_NTSC; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -175,13 +392,28 @@ static int ths7303_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev), GFP_KERNEL); - if (sd == NULL) + state = devm_kzalloc(&client->dev, sizeof(struct ths7303_state), + GFP_KERNEL); + if (!state) return -ENOMEM; + if (!pdata) + v4l_warn(client, "No platform data, using default data!\n"); + else + state->pdata = *pdata; + + sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &ths7303_ops); - return ths7303_s_std_output(sd, std_id); + /* store the driver data to differntiate the chip */ + state->driver_data = (int)id->driver_data; + + if (ths7303_setup(sd) < 0) { + v4l_err(client, "init failed\n"); + return -EIO; + } + + return 0; } static int ths7303_remove(struct i2c_client *client) @@ -194,7 +426,8 @@ static int ths7303_remove(struct i2c_client *client) } static const struct i2c_device_id ths7303_id[] = { - {"ths7303", 0}, + {"ths7303", V4L2_IDENT_THS7303}, + {"ths7353", V4L2_IDENT_THS7353}, {}, }; @@ -203,7 +436,7 @@ MODULE_DEVICE_TABLE(i2c, ths7303_id); static struct i2c_driver ths7303_driver = { .driver = { .owner = THIS_MODULE, - .name = "ths7303", + .name = "ths73x3", }, .probe = ths7303_probe, .remove = ths7303_remove, diff --git a/include/media/ths7303.h b/include/media/ths7303.h new file mode 100644 index 000000000000..980ec51d574d --- /dev/null +++ b/include/media/ths7303.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Texas Instruments Inc + * + * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. + * + * Contributors: + * Hans Verkuil + * Lad, Prabhakar + * Martin Bugge + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef THS7353_H +#define THS7353_H + +/** + * struct ths7303_platform_data - Platform dependent data + * @ch_1: Bias value for channel one. + * @ch_2: Bias value for channel two. + * @ch_3: Bias value for channel three. + * @init_enable: initalize on init. + */ +struct ths7303_platform_data { + u8 ch_1; + u8 ch_2; + u8 ch_3; + u8 init_enable; +}; + +#endif diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index b5996f959a31..c259b36bf1e9 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -188,6 +188,9 @@ enum { /* module adv7343: just ident 7343 */ V4L2_IDENT_ADV7343 = 7343, + /* module ths7353: just ident 7353 */ + V4L2_IDENT_THS7353 = 7353, + /* module adv7393: just ident 7393 */ V4L2_IDENT_ADV7393 = 7393, -- cgit v1.2.3 From e64171b97b88a1adf297d429826fdbb9e232ab53 Mon Sep 17 00:00:00 2001 From: Manjunath Hadli Date: Thu, 7 Feb 2013 13:48:51 -0300 Subject: [media] media: add support for decoder as one of media entity types A lot of SOCs including Texas Instruments Davinci family mainly use video decoders as input devices. This patch adds a flag 'MEDIA_ENT_T_V4L2_SUBDEV_DECODER' media entity type for decoder's. Along side updates the documentation for this media entity type. Signed-off-by: Manjunath Hadli Signed-off-by: Lad, Prabhakar Reviewed-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml | 10 ++++++++++ include/uapi/linux/media.h | 2 ++ 2 files changed, 12 insertions(+) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml index 576b68b33f2c..116c301656e0 100644 --- a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml @@ -272,6 +272,16 @@ MEDIA_ENT_T_V4L2_SUBDEV_LENS Lens controller + + MEDIA_ENT_T_V4L2_SUBDEV_DECODER + Video decoder, the basic function of the video decoder is to + accept analogue video from a wide variety of sources such as + broadcast, DVD players, cameras and video cassette recorders, in + either NTSC, PAL or HD format and still occasionally SECAM, separate + it into its component parts, luminance and chrominance, and output + it in some digital video standard, with appropriate embedded timing + signals. + diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 0ef883327de2..ed49574ad757 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -56,6 +56,8 @@ struct media_device_info { #define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1) #define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2) #define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3) +/* A converter of analogue video to its digital representation. */ +#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4) #define MEDIA_ENT_FL_DEFAULT (1 << 0) -- cgit v1.2.3 From 9719afae5e589b409e137c36f89073d134f0de33 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Wed, 6 Mar 2013 16:52:05 -0300 Subject: [media] rc-core: don't treat dev->rc_map.rc_type as a bitmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit store_protocols() treats dev->rc_map.rc_type as a bitmap which is wrong for two reasons. First of all, it is pretty bogus to change the protocol type of the keymap just because the hardware has been asked to decode a different protocol. Second, dev->rc_map.rc_type is an enum (i.e. a single protocol) as pointed out by James Hogan . Fix both issues by introducing a separate enabled_protocols member to struct rc_dev. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 1 + drivers/media/rc/ir-jvc-decoder.c | 2 +- drivers/media/rc/ir-lirc-codec.c | 2 +- drivers/media/rc/ir-mce_kbd-decoder.c | 2 +- drivers/media/rc/ir-nec-decoder.c | 2 +- drivers/media/rc/ir-raw.c | 2 +- drivers/media/rc/ir-rc5-decoder.c | 6 +++--- drivers/media/rc/ir-rc5-sz-decoder.c | 2 +- drivers/media/rc/ir-rc6-decoder.c | 2 +- drivers/media/rc/ir-sanyo-decoder.c | 2 +- drivers/media/rc/ir-sony-decoder.c | 8 ++++---- drivers/media/rc/rc-core-priv.h | 1 - drivers/media/rc/rc-main.c | 32 ++++++++++---------------------- include/media/rc-core.h | 2 ++ 14 files changed, 28 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 08ae067b2b6f..2586e46f14b5 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -423,6 +423,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ rc->map_name = ir->ir_codes; rc->allowed_protos = rc_type; + rc->enabled_protocols = rc_type; if (!rc->driver_name) rc->driver_name = MODULE_NAME; diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 69edffb9fe9a..3948138ca870 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct jvc_dec *data = &dev->raw->jvc; - if (!(dev->raw->enabled_protocols & RC_BIT_JVC)) + if (!(dev->enabled_protocols & RC_BIT_JVC)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 9945e5e7f61a..ff4d93d1907f 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!(dev->raw->enabled_protocols & RC_BIT_LIRC)) + if (!(dev->enabled_protocols & RC_BIT_LIRC)) return 0; if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 33fafa4cf7cb..9f3c9b59f30c 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; unsigned long delay; - if (!(dev->raw->enabled_protocols & RC_BIT_MCE_KBD)) + if (!(dev->enabled_protocols & RC_BIT_MCE_KBD)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index a47ee3634969..9a9009411439 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 address, not_address, command, not_command; bool send_32bits = false; - if (!(dev->raw->enabled_protocols & RC_BIT_NEC)) + if (!(dev->enabled_protocols & RC_BIT_NEC)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 17c94be9f24c..5c42750c7b71 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -256,7 +256,7 @@ int ir_raw_event_register(struct rc_dev *dev) return -ENOMEM; dev->raw->dev = dev; - dev->raw->enabled_protocols = ~0; + dev->enabled_protocols = ~0; rc = kfifo_alloc(&dev->raw->kfifo, sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, GFP_KERNEL); diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 5b4d1ddeac4e..4e53a319c5d8 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -52,7 +52,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle; u32 scancode; - if (!(dev->raw->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X))) + if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X))) return 0; if (!is_timing_event(ev)) { @@ -128,7 +128,7 @@ again: if (data->wanted_bits == RC5X_NBITS) { /* RC5X */ u8 xdata, command, system; - if (!(dev->raw->enabled_protocols & RC_BIT_RC5X)) { + if (!(dev->enabled_protocols & RC_BIT_RC5X)) { data->state = STATE_INACTIVE; return 0; } @@ -145,7 +145,7 @@ again: } else { /* RC5 */ u8 command, system; - if (!(dev->raw->enabled_protocols & RC_BIT_RC5)) { + if (!(dev->enabled_protocols & RC_BIT_RC5)) { data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c index fd807a8308d8..865fe84fd854 100644 --- a/drivers/media/rc/ir-rc5-sz-decoder.c +++ b/drivers/media/rc/ir-rc5-sz-decoder.c @@ -48,7 +48,7 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle, command, system; u32 scancode; - if (!(dev->raw->enabled_protocols & RC_BIT_RC5_SZ)) + if (!(dev->enabled_protocols & RC_BIT_RC5_SZ)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index e19072ffb36c..7cba7d33a3fa 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -89,7 +89,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 toggle; - if (!(dev->raw->enabled_protocols & + if (!(dev->enabled_protocols & (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE))) return 0; diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index 7e69a3b65370..0a06205b5677 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 address, command, not_command; - if (!(dev->raw->enabled_protocols & RC_BIT_SANYO)) + if (!(dev->enabled_protocols & RC_BIT_SANYO)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index fb914342cf4d..29ab9c2db060 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -45,7 +45,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 device, subdevice, function; - if (!(dev->raw->enabled_protocols & + if (!(dev->enabled_protocols & (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20))) return 0; @@ -124,7 +124,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) switch (data->count) { case 12: - if (!(dev->raw->enabled_protocols & RC_BIT_SONY12)) { + if (!(dev->enabled_protocols & RC_BIT_SONY12)) { data->state = STATE_INACTIVE; return 0; } @@ -133,7 +133,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) function = bitrev8((data->bits >> 4) & 0xFE); break; case 15: - if (!(dev->raw->enabled_protocols & RC_BIT_SONY15)) { + if (!(dev->enabled_protocols & RC_BIT_SONY15)) { data->state = STATE_INACTIVE; return 0; } @@ -142,7 +142,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) function = bitrev8((data->bits >> 7) & 0xFE); break; case 20: - if (!(dev->raw->enabled_protocols & RC_BIT_SONY20)) { + if (!(dev->enabled_protocols & RC_BIT_SONY20)) { data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 5d87287ed372..70a180bb0bd0 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -39,7 +39,6 @@ struct ir_raw_event_ctrl { ktime_t last_event; /* when last event occurred */ enum raw_event_type last_type; /* last event type */ struct rc_dev *dev; /* pointer to the parent rc_dev */ - u64 enabled_protocols; /* enabled raw protocol decoders */ /* raw decoder state follows */ struct ir_raw_event prev_ev; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f3047920b8c0..1cf382a0b277 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -783,13 +783,12 @@ static ssize_t show_protocols(struct device *device, mutex_lock(&dev->lock); - if (dev->driver_type == RC_DRIVER_SCANCODE) { - enabled = dev->rc_map.rc_type; + enabled = dev->enabled_protocols; + if (dev->driver_type == RC_DRIVER_SCANCODE) allowed = dev->allowed_protos; - } else if (dev->raw) { - enabled = dev->raw->enabled_protocols; + else if (dev->raw) allowed = ir_raw_get_allowed_protocols(); - } else { + else { mutex_unlock(&dev->lock); return -ENODEV; } @@ -847,7 +846,6 @@ static ssize_t store_protocols(struct device *device, u64 type; u64 mask; int rc, i, count = 0; - unsigned long flags; ssize_t ret; /* Device is being removed */ @@ -856,15 +854,12 @@ static ssize_t store_protocols(struct device *device, mutex_lock(&dev->lock); - if (dev->driver_type == RC_DRIVER_SCANCODE) - type = dev->rc_map.rc_type; - else if (dev->raw) - type = dev->raw->enabled_protocols; - else { + if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) { IR_dprintk(1, "Protocol switching not supported\n"); ret = -EINVAL; goto out; } + type = dev->enabled_protocols; while ((tmp = strsep((char **) &data, " \n")) != NULL) { if (!*tmp) @@ -922,14 +917,7 @@ static ssize_t store_protocols(struct device *device, } } - if (dev->driver_type == RC_DRIVER_SCANCODE) { - spin_lock_irqsave(&dev->rc_map.lock, flags); - dev->rc_map.rc_type = type; - spin_unlock_irqrestore(&dev->rc_map.lock, flags); - } else { - dev->raw->enabled_protocols = type; - } - + dev->enabled_protocols = type; IR_dprintk(1, "Current protocol(s): 0x%llx\n", (long long)type); @@ -1068,9 +1056,8 @@ int rc_register_device(struct rc_dev *dev) /* * Take the lock here, as the device sysfs node will appear * when device_add() is called, which may trigger an ir-keytable udev - * rule, which will in turn call show_protocols and access either - * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has - * been initialized. + * rule, which will in turn call show_protocols and access + * dev->enabled_protocols before it has been initialized. */ mutex_lock(&dev->lock); @@ -1132,6 +1119,7 @@ int rc_register_device(struct rc_dev *dev) rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; + dev->enabled_protocols = rc_type; } mutex_unlock(&dev->lock); diff --git a/include/media/rc-core.h b/include/media/rc-core.h index f03445f3c767..06a75deff553 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -51,6 +51,7 @@ enum rc_driver_type { * @driver_type: specifies if protocol decoding is done in hardware or software * @idle: used to keep track of RX state * @allowed_protos: bitmask with the supported RC_BIT_* protocols + * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols * @scanmask: some hardware decoders are not capable of providing the full * scancode to the application. As this is a hardware limit, we can't do * anything with it. Yet, as the same keycode table can be used with other @@ -99,6 +100,7 @@ struct rc_dev { enum rc_driver_type driver_type; bool idle; u64 allowed_protos; + u64 enabled_protocols; u32 scanmask; void *priv; spinlock_t keylock; -- cgit v1.2.3 From b530a447bb588fdf43fdf4eb909e4ee1921d47ac Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 19 Mar 2013 04:09:26 -0300 Subject: [media] v4l2: add const to argument of write-only s_frequency ioctl This ioctl is defined as IOW, so pass the argument as const. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 2 +- drivers/media/i2c/msp3400-driver.c | 2 +- drivers/media/i2c/tvaudio.c | 2 +- drivers/media/i2c/upd64031a.c | 2 +- drivers/media/i2c/wm8775.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 14 ++++---- drivers/media/pci/cx18/cx18-av-core.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.h | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 2 +- drivers/media/pci/cx23885/cx23885-video.c | 8 ++--- drivers/media/pci/cx23885/cx23885.h | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 4 +-- drivers/media/pci/cx25821/cx25821-video.h | 4 +-- drivers/media/pci/cx88/cx88-blackbird.c | 2 +- drivers/media/pci/cx88/cx88-video.c | 10 +++--- drivers/media/pci/cx88/cx88.h | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.h | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 2 +- drivers/media/pci/saa7146/mxb.c | 4 +-- drivers/media/pci/saa7164/saa7164-encoder.c | 2 +- drivers/media/pci/saa7164/saa7164-vbi.c | 2 +- drivers/media/pci/ttpci/av7110_v4l.c | 2 +- drivers/media/radio/dsbr100.c | 2 +- drivers/media/radio/radio-cadet.c | 46 ++++++++++++------------ drivers/media/radio/radio-isa.c | 9 ++--- drivers/media/radio/radio-keene.c | 8 ++--- drivers/media/radio/radio-ma901.c | 2 +- drivers/media/radio/radio-miropcm20.c | 4 +-- drivers/media/radio/radio-mr800.c | 2 +- drivers/media/radio/radio-sf16fmi.c | 2 +- drivers/media/radio/radio-si4713.c | 2 +- drivers/media/radio/radio-tea5764.c | 2 +- drivers/media/radio/radio-tea5777.c | 2 +- drivers/media/radio/radio-timb.c | 2 +- drivers/media/radio/radio-wl1273.c | 2 +- drivers/media/radio/si470x/radio-si470x-common.c | 2 +- drivers/media/radio/si4713-i2c.c | 5 ++- drivers/media/radio/tef6862.c | 2 +- drivers/media/radio/wl128x/fmdrv_v4l2.c | 6 ++-- drivers/media/usb/au0828/au0828-video.c | 2 +- drivers/media/usb/cx231xx/cx231xx-video.c | 7 ++-- drivers/media/usb/cx231xx/cx231xx.h | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 7 ++-- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/usb/tlg2300/pd-radio.c | 2 +- drivers/media/usb/tlg2300/pd-video.c | 5 +-- drivers/media/usb/tm6000/tm6000-video.c | 2 +- drivers/media/usb/usbvision/usbvision-video.c | 2 +- drivers/media/v4l2-core/tuner-core.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- drivers/staging/media/go7007/go7007-v4l2.c | 2 +- include/media/v4l2-ioctl.h | 2 +- include/media/v4l2-subdev.h | 2 +- sound/i2c/other/tea575x-tuner.c | 4 +-- 56 files changed, 115 insertions(+), 110 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f4149eb4d7b4..f4339ed8f2e5 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1835,7 +1835,7 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, return set_input(client, state->vid_input, input); } -static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int cx25840_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 766305f69a28..77053ba09627 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -445,7 +445,7 @@ static int msp_s_radio(struct v4l2_subdev *sd) return 0; } -static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int msp_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 4c91b355b55a..4b12c5188075 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1817,7 +1817,7 @@ static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std) return 0; } -static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int tvaudio_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c index 1e7446542091..d15cfd944e57 100644 --- a/drivers/media/i2c/upd64031a.c +++ b/drivers/media/i2c/upd64031a.c @@ -111,7 +111,7 @@ static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val) /* ------------------------------------------------------------------------ */ /* The input changed due to new input or channel changed */ -static int upd64031a_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int upd64031a_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct upd64031a_state *state = to_state(sd); u8 reg = state->regs[R00]; diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c index bee77ea9f49e..27c27b4ae238 100644 --- a/drivers/media/i2c/wm8775.c +++ b/drivers/media/i2c/wm8775.c @@ -174,7 +174,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd) return 0; } -static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int wm8775_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { wm8775_set_audio(sd, 0); return 0; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 2fb2168f74e2..3156daf2c804 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1852,24 +1852,26 @@ static int bttv_g_frequency(struct file *file, void *priv, return 0; } -static void bttv_set_frequency(struct bttv *btv, struct v4l2_frequency *f) +static void bttv_set_frequency(struct bttv *btv, const struct v4l2_frequency *f) { + struct v4l2_frequency new_freq = *f; + bttv_call_all(btv, tuner, s_frequency, f); /* s_frequency may clamp the frequency, so get the actual frequency before assigning radio/tv_freq. */ - bttv_call_all(btv, tuner, g_frequency, f); - if (f->type == V4L2_TUNER_RADIO) { + bttv_call_all(btv, tuner, g_frequency, &new_freq); + if (new_freq.type == V4L2_TUNER_RADIO) { radio_enable(btv); - btv->radio_freq = f->frequency; + btv->radio_freq = new_freq.frequency; if (btv->has_matchbox) tea5757_set_freq(btv, btv->radio_freq); } else { - btv->tv_freq = f->frequency; + btv->tv_freq = new_freq.frequency; } } static int bttv_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index f164b7f610a5..a2c51e0468a8 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -576,7 +576,7 @@ static void input_change(struct cx18 *cx) } static int cx18_av_s_frequency(struct v4l2_subdev *sd, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct cx18 *cx = v4l2_get_subdevdata(sd); input_change(cx); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index cd8d2c2b1624..5cd22e7095e6 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -614,7 +614,7 @@ static int cx18_g_frequency(struct file *file, void *fh, return 0; } -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; diff --git a/drivers/media/pci/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h index 2f9dd591ee0f..aa9b44a611d3 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.h +++ b/drivers/media/pci/cx18/cx18-ioctl.h @@ -27,5 +27,5 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); void cx18_set_funcs(struct video_device *vdev); int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int cx18_s_input(struct file *file, void *fh, unsigned int inp); diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 5d5052d0253f..84a1b75d5444 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1311,7 +1311,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { return cx23885_set_frequency(file, priv, f); } diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 5991bc8dc158..5ba15b8dafe0 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1518,7 +1518,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) +static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f) { struct v4l2_control ctrl; @@ -1550,7 +1550,7 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) } static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct v4l2_control ctrl; struct videobuf_dvb_frontend *vfe; @@ -1608,7 +1608,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, } int cx23885_set_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; @@ -1628,7 +1628,7 @@ int cx23885_set_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { return cx23885_set_frequency(file, priv, f); } diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 59c322d870f2..5687d3f678db 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -587,7 +587,7 @@ extern void cx23885_video_wakeup(struct cx23885_dev *dev, int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); int cx23885_set_input(struct file *file, void *priv, unsigned int i); int cx23885_get_input(struct file *file, void *priv, unsigned int *i); -int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f); +int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f); int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index d4de021dc844..1219d60cdd79 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1312,7 +1312,7 @@ int cx25821_vidioc_g_frequency(struct file *file, void *priv, return 0; } -int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f) +int cx25821_set_freq(struct cx25821_dev *dev, const struct v4l2_frequency *f) { mutex_lock(&dev->lock); dev->freq = f->frequency; @@ -1328,7 +1328,7 @@ int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f) } int cx25821_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx25821_fh *fh = priv; struct cx25821_dev *dev; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index c265e35b37c3..969340c2dcfa 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -149,9 +149,9 @@ extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); extern int cx25821_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f); -extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f); +extern int cx25821_set_freq(struct cx25821_dev *dev, const struct v4l2_frequency *f); extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f); + const struct v4l2_frequency *f); extern int cx25821_vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg); extern int cx25821_vidioc_s_register(struct file *file, void *fh, diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index a6ff8a6f4fc0..82aa11f526f0 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -815,7 +815,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) } static int vidioc_s_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx8802_fh *fh = priv; struct cx8802_dev *dev = fh->dev; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index bc78354262ac..4f10875295e8 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1321,8 +1321,10 @@ static int vidioc_g_frequency (struct file *file, void *priv, } int cx88_set_freq (struct cx88_core *core, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { + struct v4l2_frequency new_freq = *f; + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) @@ -1331,8 +1333,8 @@ int cx88_set_freq (struct cx88_core *core, mutex_lock(&core->lock); cx88_newstation(core); call_all(core, tuner, s_frequency, f); - call_all(core, tuner, g_frequency, f); - core->freq = f->frequency; + call_all(core, tuner, g_frequency, &new_freq); + core->freq = new_freq.frequency; /* When changing channels it is required to reset TVAUDIO */ msleep (10); @@ -1345,7 +1347,7 @@ int cx88_set_freq (struct cx88_core *core, EXPORT_SYMBOL(cx88_set_freq); static int vidioc_s_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index feff53c0a251..eca02c2435de 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -740,7 +740,7 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev); /* ----------------------------------------------------------- */ /* cx88-video.c*/ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i); -int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f); +int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f); int cx88_video_mux(struct cx88_core *core, unsigned int input); void cx88_querycap(struct file *file, struct cx88_core *core, struct v4l2_capability *cap); diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 7a8b0d0b6127..e6258b68d22c 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1078,7 +1078,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency * return 0; } -int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) { struct ivtv *itv = fh2id(fh)->itv; struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h index 7c553d16579b..34c6bc132ebd 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.h +++ b/drivers/media/pci/ivtv/ivtv-ioctl.h @@ -29,7 +29,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed); void ivtv_set_funcs(struct video_device *vdev); void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std); void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std); -int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int ivtv_s_input(struct file *file, void *fh, unsigned int inp); #endif diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 7c503fb68526..6c619d13f731 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2057,7 +2057,7 @@ static int saa7134_g_frequency(struct file *file, void *priv, } static int saa7134_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 91369daad722..27dc49b03d02 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -595,7 +595,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency return 0; } -static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; @@ -612,8 +612,8 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency /* tune in desired frequency */ tuner_call(mxb, tuner, s_frequency, f); /* let the tuner subdev clamp the frequency to the tuner range */ - tuner_call(mxb, tuner, g_frequency, f); mxb->cur_freq = *f; + tuner_call(mxb, tuner, g_frequency, &mxb->cur_freq); if (mxb->cur_audinput == 0) mxb_update_audmode(mxb); diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 9bb0903ee5f1..34f700da2e7a 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -337,7 +337,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct saa7164_encoder_fh *fh = file->private_data; struct saa7164_port *port = fh->port; diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index b4532299c0ed..5a8a6adb894b 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -309,7 +309,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct saa7164_vbi_fh *fh = file->private_data; struct saa7164_port *port = fh->port; diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c index 730e906ea912..65adaa74c511 100644 --- a/drivers/media/pci/ttpci/av7110_v4l.c +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -426,7 +426,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency return 0; } -static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 63b112b555b2..e140a725820d 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -214,7 +214,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct dsbr100_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 643d80ac28fb..59be293cbf42 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -90,6 +90,26 @@ static u16 sigtable[2][4] = { { 2185, 4369, 13107, 65535 }, }; +static const struct v4l2_frequency_band bands[] = { + { + .index = 0, + .type = V4L2_TUNER_RADIO, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 8320, /* 520 kHz */ + .rangehigh = 26400, /* 1650 kHz */ + .modulation = V4L2_BAND_MODULATION_AM, + }, { + .index = 1, + .type = V4L2_TUNER_RADIO, + .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW | + V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 1400000, /* 87.5 MHz */ + .rangehigh = 1728000, /* 108.0 MHz */ + .modulation = V4L2_BAND_MODULATION_FM, + }, +}; + static int cadet_getstereo(struct cadet *dev) { @@ -196,6 +216,8 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) int i, j, test; int curvol; + freq = clamp(freq, bands[dev->is_fm_band].rangelow, + bands[dev->is_fm_band].rangehigh); dev->curfreq = freq; /* * Formulate a fifo command @@ -337,26 +359,6 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static const struct v4l2_frequency_band bands[] = { - { - .index = 0, - .type = V4L2_TUNER_RADIO, - .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 8320, /* 520 kHz */ - .rangehigh = 26400, /* 1650 kHz */ - .modulation = V4L2_BAND_MODULATION_AM, - }, { - .index = 1, - .type = V4L2_TUNER_RADIO, - .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW | - V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 1400000, /* 87.5 MHz */ - .rangehigh = 1728000, /* 108.0 MHz */ - .modulation = V4L2_BAND_MODULATION_FM, - }, -}; - static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { @@ -418,7 +420,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cadet *dev = video_drvdata(file); @@ -426,8 +428,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, return -EINVAL; dev->is_fm_band = f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2; - clamp(f->frequency, bands[dev->is_fm_band].rangelow, - bands[dev->is_fm_band].rangehigh); cadet_setfreq(dev, f->frequency); return 0; } diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index fe0a4f85c422..0c1e27b13e69 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -102,17 +102,18 @@ static int radio_isa_s_tuner(struct file *file, void *priv, } static int radio_isa_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct radio_isa_card *isa = video_drvdata(file); + u32 freq = f->frequency; int res; if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH); - res = isa->drv->ops->s_frequency(isa, f->frequency); + freq = clamp(freq, FREQ_LOW, FREQ_HIGH); + res = isa->drv->ops->s_frequency(isa, freq); if (res == 0) - isa->freq = f->frequency; + isa->freq = freq; return res; } diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index 296941a9ae25..4c9ae767fb31 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -215,15 +215,15 @@ static int vidioc_s_modulator(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct keene_device *radio = video_drvdata(file); + unsigned freq = f->frequency; if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - f->frequency = clamp(f->frequency, - FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); - return keene_cmd_main(radio, f->frequency, true); + freq = clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); + return keene_cmd_main(radio, freq, true); } static int vidioc_g_frequency(struct file *file, void *priv, diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index c61f590029ad..7f85c6f98009 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -257,7 +257,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, /* vidioc_s_frequency - set tuner radio frequency */ static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct ma901radio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 3d0ff4404d12..2b8d31d8330b 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -131,14 +131,14 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct pcm20 *dev = video_drvdata(file); if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - dev->freq = clamp(f->frequency, 87 * 16000U, 108 * 16000U); + dev->freq = clamp_t(u32, f->frequency, 87 * 16000U, 108 * 16000U); pcm20_setfreq(dev, dev->freq); return 0; } diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 9c5a267b60b4..f9cdd8b96add 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -323,7 +323,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, /* vidioc_s_frequency - set tuner radio frequency */ static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct amradio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 637a55564958..6142b5b3e81b 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -151,7 +151,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct fmi *fmi = video_drvdata(file); diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 3df4339460d2..2a2d21ed9133 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -215,7 +215,7 @@ static int radio_si4713_g_frequency(struct file *file, void *p, } static int radio_si4713_s_frequency(struct file *file, void *p, - struct v4l2_frequency *vf) + const struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, s_frequency, vf); diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 1978516af67e..893842874d89 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -351,7 +351,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct tea5764_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c index 4b5190d4fea5..fcd7c195e0c5 100644 --- a/drivers/media/radio/radio-tea5777.c +++ b/drivers/media/radio/radio-tea5777.c @@ -368,7 +368,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct radio_tea5777 *tea = video_drvdata(file); diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index b87effeb5dc6..1712c05c113d 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -91,7 +91,7 @@ static int timbradio_vidioc_s_audio(struct file *file, void *priv, } static int timbradio_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct timbradio *tr = video_drvdata(file); return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 02151e0e6e63..9a02fee904bf 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1640,7 +1640,7 @@ static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv, } static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); struct wl1273_core *core = radio->core; diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 18989388ddc1..5708633a3d78 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -678,7 +678,7 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv, * si470x_vidioc_s_frequency - set tuner or modulator radio frequency */ static int si470x_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct si470x_device *radio = video_drvdata(file); int retval; diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index bd61b3bd0ca3..e305c14272b5 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1212,7 +1212,7 @@ exit: return rval; } -static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f); +static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f); static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulator *); /* * si4713_setup - Sets the device up with current configuration. @@ -1950,7 +1950,7 @@ unlock: } /* si4713_s_frequency - set tuner or modulator radio frequency */ -static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f) { struct si4713_device *sdev = to_si4713_device(sd); int rval = 0; @@ -1970,7 +1970,6 @@ static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) rval = 0; } sdev->frequency = frequency; - f->frequency = si4713_to_v4l2(frequency); unlock: mutex_unlock(&sdev->mutex); diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index b18c2dc268ba..867395568f92 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -101,7 +101,7 @@ static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) return v->index ? -EINVAL : 0; } -static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f) { struct tef6862_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 0a8ee8fab924..0183956d9b02 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -388,7 +388,7 @@ static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv, /* Set tuner or modulator radio frequency */ static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct fmdev *fmdev = video_drvdata(file); @@ -396,9 +396,7 @@ static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency * in units of 62.5 Hz. */ - freq->frequency = (u32)(freq->frequency / 16); - - return fmc_set_freq(fmdev, freq->frequency); + return fmc_set_freq(fmdev, freq->frequency / 16); } /* Set hardware frequency seek. If current mode is NOT RX, set it RX. */ diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 8b9e8268e911..b1d6b034e1a1 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1545,7 +1545,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index ac6200870a62..96f65318d788 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1172,10 +1172,11 @@ int cx231xx_g_frequency(struct file *file, void *priv, } int cx231xx_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + struct v4l2_frequency new_freq = *f; int rc; u32 if_frequency = 5400000; @@ -1194,8 +1195,8 @@ int cx231xx_s_frequency(struct file *file, void *priv, rc = cx231xx_tuner_pre_channel_change(dev); call_all(dev, tuner, s_frequency, f); - call_all(dev, tuner, g_frequency, f); - dev->ctl_freq = f->frequency; + call_all(dev, tuner, g_frequency, &new_freq); + dev->ctl_freq = new_freq.frequency; /* set post channel change settings in DIF first */ rc = cx231xx_tuner_post_channel_change(dev); diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index dff3f1d73f28..6f701e9bec44 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -940,7 +940,7 @@ int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t); int cx231xx_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f); int cx231xx_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f); + const struct v4l2_frequency *f); int cx231xx_enum_input(struct file *file, void *priv, struct v4l2_input *i); int cx231xx_g_input(struct file *file, void *priv, unsigned int *i); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index d585c19a5d9c..af79089a0169 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1221,8 +1221,9 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { + struct v4l2_frequency new_freq = *f; struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1230,8 +1231,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, return -EINVAL; v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); - dev->ctl_freq = f->frequency; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq); + dev->ctl_freq = new_freq.frequency; return 0; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 34c3b6e80e86..75657c6dc013 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -365,7 +365,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) vt->audmode); } -static int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) +static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 0f958f74dbc4..8b1daf1f1e99 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -252,7 +252,7 @@ error: } static int fm_set_freq(struct file *file, void *priv, - struct v4l2_frequency *argp) + const struct v4l2_frequency *argp) { struct poseidon *p = video_drvdata(file); diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index dab0ca32d396..8ef7c8c419f7 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -1079,10 +1079,11 @@ static int set_frequency(struct poseidon *pd, u32 *frequency) } static int vidioc_s_frequency(struct file *file, void *fh, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct front_face *front = fh; struct poseidon *pd = front->pd; + u32 frequency = freq->frequency; if (freq->tuner) return -EINVAL; @@ -1090,7 +1091,7 @@ static int vidioc_s_frequency(struct file *file, void *fh, pd->pm_suspend = pm_video_suspend; pd->pm_resume = pm_video_resume; #endif - return set_frequency(pd, &freq->frequency); + return set_frequency(pd, &frequency); } static int vidioc_reqbufs(struct file *file, void *fh, diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 1a6857929c15..49df7537fa63 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1255,7 +1255,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index cd1fe78a5532..b66844564144 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -657,7 +657,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct usb_usbvision *usbvision = video_drvdata(file); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index b5a8aac2e126..279f65efe9ba 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1134,7 +1134,7 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) return 0; } -static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +static int tuner_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f) { struct tuner *t = to_tuner(sd); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index aa6e7c788db2..8ec8abe0ffe7 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1316,7 +1316,7 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { struct video_device *vfd = video_devdata(file); - struct v4l2_frequency *p = arg; + const struct v4l2_frequency *p = arg; enum v4l2_tuner_type type; type = (vfd->vfl_type == VFL_TYPE_RADIO) ? diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index cb9fe33050c7..1288f1cab129 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1281,7 +1281,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct go7007 *go = ((struct go7007_file *) priv)->go; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 4118ad1324c9..f06436dbaf75 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -223,7 +223,7 @@ struct v4l2_ioctl_ops { int (*vidioc_g_frequency) (struct file *file, void *fh, struct v4l2_frequency *a); int (*vidioc_s_frequency) (struct file *file, void *fh, - struct v4l2_frequency *a); + const struct v4l2_frequency *a); int (*vidioc_enum_freq_bands) (struct file *file, void *fh, struct v4l2_frequency_band *band); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index b137a5e1151a..1a82a50ea9c8 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -191,7 +191,7 @@ struct v4l2_subdev_core_ops { */ struct v4l2_subdev_tuner_ops { int (*s_radio)(struct v4l2_subdev *sd); - int (*s_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); + int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 3c6c1e3226f3..738c5ad9c93f 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -336,7 +336,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct snd_tea575x *tea = video_drvdata(file); @@ -350,7 +350,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, else tea->band = BAND_FM; - tea->freq = clamp(f->frequency, bands[tea->band].rangelow, + tea->freq = clamp_t(u32, f->frequency, bands[tea->band].rangelow, bands[tea->band].rangehigh); snd_tea575x_set_freq(tea); return 0; -- cgit v1.2.3 From 2f73c7c582a685b3198b974cd6d964d0338f8ab5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 06:10:06 -0300 Subject: [media] v4l2: add const to argument of write-only s_tuner ioctl This ioctl is defined as IOW, so pass the argument as const. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Acked-by: Alexey Klimov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 2 +- drivers/media/i2c/msp3400-driver.c | 2 +- drivers/media/i2c/saa6588.c | 2 +- drivers/media/i2c/saa717x.c | 2 +- drivers/media/i2c/tda9840.c | 2 +- drivers/media/i2c/tvaudio.c | 2 +- drivers/media/i2c/vp27smpx.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 11 +++++++---- drivers/media/pci/cx18/cx18-av-core.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 2 +- drivers/media/pci/cx23885/cx23885-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.h | 2 +- drivers/media/pci/cx88/cx88-blackbird.c | 2 +- drivers/media/pci/cx88/cx88-video.c | 9 ++------- drivers/media/pci/ivtv/ivtv-gpio.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 4 ++-- drivers/media/pci/saa7146/mxb.c | 2 +- drivers/media/pci/saa7164/saa7164-encoder.c | 2 +- drivers/media/pci/saa7164/saa7164-vbi.c | 2 +- drivers/media/pci/ttpci/av7110_v4l.c | 2 +- drivers/media/radio/dsbr100.c | 2 +- drivers/media/radio/radio-cadet.c | 2 +- drivers/media/radio/radio-isa.c | 2 +- drivers/media/radio/radio-ma901.c | 2 +- drivers/media/radio/radio-miropcm20.c | 8 +++++--- drivers/media/radio/radio-mr800.c | 2 +- drivers/media/radio/radio-sf16fmi.c | 2 +- drivers/media/radio/radio-tea5764.c | 2 +- drivers/media/radio/radio-tea5777.c | 7 +++---- drivers/media/radio/radio-timb.c | 2 +- drivers/media/radio/radio-wl1273.c | 2 +- drivers/media/radio/si470x/radio-si470x-common.c | 2 +- drivers/media/radio/tef6862.c | 2 +- drivers/media/radio/wl128x/fmdrv_v4l2.c | 2 +- drivers/media/usb/au0828/au0828-video.c | 4 +--- drivers/media/usb/cx231xx/cx231xx-video.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx.h | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/usb/tlg2300/pd-radio.c | 2 +- drivers/media/usb/tlg2300/pd-video.c | 2 +- drivers/media/usb/tm6000/tm6000-video.c | 8 ++------ drivers/media/usb/usbvision/usbvision-video.c | 2 +- drivers/media/v4l2-core/tuner-core.c | 2 +- drivers/staging/media/go7007/go7007-v4l2.c | 2 +- include/media/v4l2-ioctl.h | 2 +- include/media/v4l2-subdev.h | 2 +- sound/i2c/other/tea575x-tuner.c | 2 +- 51 files changed, 68 insertions(+), 75 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f4339ed8f2e5..234b7c63d087 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1881,7 +1881,7 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 77053ba09627..54a9dd394f45 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -535,7 +535,7 @@ static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int msp_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 0caac50d7cf4..b4e1ccbd87ec 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c @@ -435,7 +435,7 @@ static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct saa6588 *s = to_saa6588(sd); diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 1e84466515aa..5608b937f8b2 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -1113,7 +1113,7 @@ static int saa717x_s_stream(struct v4l2_subdev *sd, int enable) } /* change audio mode */ -static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int saa717x_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct saa717x_state *decoder = to_state(sd); int audio_mode; diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c index 3d7ddd93282d..01441e35d88b 100644 --- a/drivers/media/i2c/tda9840.c +++ b/drivers/media/i2c/tda9840.c @@ -87,7 +87,7 @@ static int tda9840_status(struct v4l2_subdev *sd) return byte & 0x60; } -static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t) +static int tda9840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *t) { int stat = tda9840_status(sd); int byte; diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 4b12c5188075..b72a59d3216a 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1761,7 +1761,7 @@ static int tvaudio_s_routing(struct v4l2_subdev *sd, return 0; } -static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int tvaudio_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c index 7cfbc9d94a48..e71f139695af 100644 --- a/drivers/media/i2c/vp27smpx.c +++ b/drivers/media/i2c/vp27smpx.c @@ -90,7 +90,7 @@ static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) return 0; } -static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int vp27smpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct vp27smpx_state *state = to_state(sd); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 3156daf2c804..7aea24bf3a37 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1820,7 +1820,7 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) } static int bttv_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -1830,8 +1830,11 @@ static int bttv_s_tuner(struct file *file, void *priv, bttv_call_all(btv, tuner, s_tuner, t); - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 1); + if (btv->audio_mode_gpio) { + struct v4l2_tuner copy = *t; + + btv->audio_mode_gpio(btv, ©, 1); + } return 0; } @@ -3279,7 +3282,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index a2c51e0468a8..c22242bc10df 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -809,7 +809,7 @@ static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int cx18_av_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct cx18_av_state *state = to_cx18_av_state(sd); struct cx18 *cx = v4l2_get_subdevdata(sd); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 5cd22e7095e6..173ccd204c1f 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -673,7 +673,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 84a1b75d5444..812ec5ff5939 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1280,7 +1280,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx23885_fh *fh = file->private_data; struct cx23885_dev *dev = fh->dev; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 5ba15b8dafe0..2bbda43eb00e 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1486,7 +1486,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 1219d60cdd79..75281c1530d8 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1397,7 +1397,7 @@ int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +int cx25821_vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; struct cx25821_fh *fh = priv; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 969340c2dcfa..f0e70ffbedd4 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -159,7 +159,7 @@ extern int cx25821_vidioc_s_register(struct file *file, void *fh, extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t); + const struct v4l2_tuner *t); extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm); extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm); diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 82aa11f526f0..486ca8d5f2a0 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -918,7 +918,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, } static int vidioc_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 4f10875295e8..ede6f139b5cc 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1289,7 +1289,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, } static int vidioc_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; @@ -1409,20 +1409,15 @@ static int radio_g_tuner (struct file *file, void *priv, return 0; } -/* FIXME: Should add a standard for radio */ - static int radio_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; if (0 != t->index) return -EINVAL; - if (t->audmode > V4L2_TUNER_MODE_STEREO) - t->audmode = V4L2_TUNER_MODE_STEREO; call_all(core, tuner, s_tuner, t); - return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c index 8f0d07789053..af52def700cc 100644 --- a/drivers/media/pci/ivtv/ivtv-gpio.c +++ b/drivers/media/pci/ivtv/ivtv-gpio.c @@ -192,7 +192,7 @@ static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int subdev_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct ivtv *itv = sd_to_ivtv(sd); u16 mask, data; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index e6258b68d22c..852f11e0d636 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1196,7 +1196,7 @@ static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +static int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 6c619d13f731..1e23547531b9 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2023,7 +2023,7 @@ static int saa7134_g_tuner(struct file *file, void *priv, } static int saa7134_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; @@ -2347,7 +2347,7 @@ static int radio_g_tuner(struct file *file, void *priv, return 0; } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 27dc49b03d02..9dd044b563e7 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -560,7 +560,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) return call_all(dev, tuner, g_tuner, t); } -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 34f700da2e7a..e7fbd036ba44 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -318,7 +318,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { /* Update the A/V core */ return 0; diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index 5a8a6adb894b..bfc8cec110de 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -290,7 +290,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { /* Update the A/V core */ return 0; diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c index 65adaa74c511..6c4076acb131 100644 --- a/drivers/media/pci/ttpci/av7110_v4l.c +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -366,7 +366,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) return 0; } -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index e140a725820d..142c2ee64d31 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -208,7 +208,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 59be293cbf42..545c04cf7226 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -390,7 +390,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index 0c1e27b13e69..6ff350831d56 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -87,7 +87,7 @@ static int radio_isa_g_tuner(struct file *file, void *priv, } static int radio_isa_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct radio_isa_card *isa = video_drvdata(file); const struct radio_isa_ops *ops = isa->drv->ops; diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index 7f85c6f98009..18320c2c4607 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -239,7 +239,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, /* vidioc_s_tuner - set tuner attributes */ static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct ma901radio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 2b8d31d8330b..a7e93d7477dd 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -103,16 +103,18 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct pcm20 *dev = video_drvdata(file); if (v->index) return -EINVAL; if (v->audmode > V4L2_TUNER_MODE_STEREO) - v->audmode = V4L2_TUNER_MODE_STEREO; + dev->audmode = V4L2_TUNER_MODE_STEREO; + else + dev->audmode = v->audmode; snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, - v->audmode == V4L2_TUNER_MODE_MONO, -1); + dev->audmode == V4L2_TUNER_MODE_MONO, -1); return 0; } diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index f9cdd8b96add..2ce75d1564dc 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -305,7 +305,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, /* vidioc_s_tuner - set tuner attributes */ static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct amradio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 6142b5b3e81b..adfcc61bdf0b 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -145,7 +145,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 893842874d89..38d563d62595 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -339,7 +339,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct tea5764_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c index fcd7c195e0c5..e2455970725a 100644 --- a/drivers/media/radio/radio-tea5777.c +++ b/drivers/media/radio/radio-tea5777.c @@ -336,7 +336,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct radio_tea5777 *tea = video_drvdata(file); u32 orig_audmode = tea->audmode; @@ -344,10 +344,9 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (v->index) return -EINVAL; - if (v->audmode > V4L2_TUNER_MODE_STEREO) - v->audmode = V4L2_TUNER_MODE_STEREO; - tea->audmode = v->audmode; + if (tea->audmode > V4L2_TUNER_MODE_STEREO) + tea->audmode = V4L2_TUNER_MODE_STEREO; if (tea->audmode != orig_audmode && tea->band == BAND_FM) return radio_tea5777_set_freq(tea); diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 1712c05c113d..bb7b143b65d1 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -56,7 +56,7 @@ static int timbradio_vidioc_g_tuner(struct file *file, void *priv, } static int timbradio_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct timbradio *tr = video_drvdata(file); return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 9a02fee904bf..97c2c18803ef 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1559,7 +1559,7 @@ out: } static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); struct wl1273_core *core = radio->core; diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 5708633a3d78..5c57e5b0f949 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -636,7 +636,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, * si470x_vidioc_s_tuner - set tuner attributes */ static int si470x_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct si470x_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 867395568f92..82c6c9475d7c 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -96,7 +96,7 @@ static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) return 0; } -static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) +static int tef6862_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 0183956d9b02..5dec323f4247 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -331,7 +331,7 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, * Should we set other tuner attributes, too? */ static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct fmdev *fmdev = video_drvdata(file); u16 aud_mode; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index b1d6b034e1a1..11316f2f2e42 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1508,7 +1508,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; @@ -1516,8 +1516,6 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (t->index != 0) return -EINVAL; - t->type = V4L2_TUNER_ANALOG_TV; - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1); diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 96f65318d788..53020a7e01fe 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1139,7 +1139,7 @@ int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -1808,7 +1808,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 6f701e9bec44..2f9faee539cb 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -936,7 +936,7 @@ void cx231xx_close_extension(struct cx231xx *dev); int cx231xx_querycap(struct file *file, void *priv, struct v4l2_capability *cap); int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); -int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t); +int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t); int cx231xx_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f); int cx231xx_s_frequency(struct file *file, void *priv, diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index af79089a0169..3ef696d36c7e 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1195,7 +1195,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1493,7 +1493,7 @@ static int radio_g_tuner(struct file *file, void *priv, } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 75657c6dc013..0f729c92e3cf 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -352,7 +352,7 @@ static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) return pvr2_hdw_get_tuner_status(hdw, vt); } -static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) +static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 8b1daf1f1e99..ea6070ba835e 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -283,7 +283,7 @@ static int tlg_fm_s_ctrl(struct v4l2_ctrl *ctrl) return -EINVAL; } -static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) +static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { return vt->index > 0 ? -EINVAL : 0; } diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 8ef7c8c419f7..9595309caed4 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -1031,7 +1031,7 @@ static int pd_vidioc_s_tuner(struct poseidon *pd, int index) return ret; } -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a) +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *a) { struct front_face *front = fh; struct poseidon *pd = front->pd; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 49df7537fa63..b4618d7d9c4b 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1215,7 +1215,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; @@ -1293,18 +1293,14 @@ static int radio_g_tuner(struct file *file, void *priv, } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct tm6000_fh *fh = file->private_data; struct tm6000_core *dev = fh->dev; if (0 != t->index) return -EINVAL; - if (t->audmode > V4L2_TUNER_MODE_STEREO) - t->audmode = V4L2_TUNER_MODE_STEREO; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - return 0; } diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index b66844564144..874cfec0b8db 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -628,7 +628,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *vt) + const struct v4l2_tuner *vt) { struct usb_usbvision *usbvision = video_drvdata(file); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 279f65efe9ba..f775768d088d 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1233,7 +1233,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) * Note: vt->type should be initialized before calling it. * This is done by either video_ioctl2 or by the bridge driver. */ -static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int tuner_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct tuner *t = to_tuner(sd); diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 1288f1cab129..4e477f3b78f3 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1242,7 +1242,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct go7007 *go = ((struct go7007_file *) priv)->go; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index f06436dbaf75..0da8682a0481 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -219,7 +219,7 @@ struct v4l2_ioctl_ops { int (*vidioc_g_tuner) (struct file *file, void *fh, struct v4l2_tuner *a); int (*vidioc_s_tuner) (struct file *file, void *fh, - struct v4l2_tuner *a); + const struct v4l2_tuner *a); int (*vidioc_g_frequency) (struct file *file, void *fh, struct v4l2_frequency *a); int (*vidioc_s_frequency) (struct file *file, void *fh, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 1a82a50ea9c8..79784fc8f9e9 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -194,7 +194,7 @@ struct v4l2_subdev_tuner_ops { int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); - int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); + int (*s_tuner)(struct v4l2_subdev *sd, const struct v4l2_tuner *vt); int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm); int (*s_modulator)(struct v4l2_subdev *sd, const struct v4l2_modulator *vm); int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type); diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 738c5ad9c93f..8a36a1d9803f 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -306,7 +306,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct snd_tea575x *tea = video_drvdata(file); u32 orig_val = tea->val; -- cgit v1.2.3 From 314527acbbb3f33f72c2ef19d8cfabcada9912a5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 06:10:40 -0300 Subject: [media] v4l2: pass std by value to the write-only s_std ioctl This ioctl is defined as IOW, so pass the argument by value instead of by reference. I could have chosen to add const instead, but this is 1) easier to handle in drivers and 2) consistent with the s_std subdev operation. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Acked-by: Jonathan Corbet Acked-by: Guennadi Liakhovetski Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_video.c | 4 ++-- drivers/media/parport/pms.c | 4 ++-- drivers/media/pci/bt8xx/bttv-driver.c | 6 +++--- drivers/media/pci/cx18/cx18-driver.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 10 +++++----- drivers/media/pci/cx18/cx18-ioctl.h | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 6 +++--- drivers/media/pci/cx23885/cx23885-video.c | 4 ++-- drivers/media/pci/cx25821/cx25821-video.c | 6 +++--- drivers/media/pci/cx25821/cx25821-video.h | 2 +- drivers/media/pci/cx88/cx88-blackbird.c | 4 ++-- drivers/media/pci/cx88/cx88-video.c | 4 ++-- drivers/media/pci/ivtv/ivtv-driver.c | 4 ++-- drivers/media/pci/ivtv/ivtv-firmware.c | 4 ++-- drivers/media/pci/ivtv/ivtv-ioctl.c | 18 +++++++++--------- drivers/media/pci/ivtv/ivtv-ioctl.h | 4 ++-- drivers/media/pci/saa7134/saa7134-empress.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 14 +++++++------- drivers/media/pci/saa7134/saa7134.h | 2 +- drivers/media/pci/saa7164/saa7164-encoder.c | 8 ++++---- drivers/media/pci/saa7164/saa7164-vbi.c | 8 ++++---- drivers/media/pci/sta2x11/sta2x11_vip.c | 18 +++++++++--------- drivers/media/pci/zoran/zoran_driver.c | 4 ++-- drivers/media/platform/blackfin/bfin_capture.c | 6 +++--- drivers/media/platform/davinci/vpbe.c | 8 ++++---- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpfe_capture.c | 12 ++++++------ drivers/media/platform/davinci/vpif_capture.c | 6 +++--- drivers/media/platform/davinci/vpif_display.c | 10 +++++----- drivers/media/platform/fsl-viu.c | 6 +++--- drivers/media/platform/marvell-ccic/mcam-core.c | 2 +- drivers/media/platform/s5p-tv/mixer_video.c | 4 ++-- drivers/media/platform/sh_vou.c | 12 ++++++------ drivers/media/platform/soc_camera/soc_camera.c | 4 ++-- drivers/media/platform/timblogiw.c | 6 +++--- drivers/media/platform/via-camera.c | 2 +- drivers/media/platform/vino.c | 10 +++++----- drivers/media/usb/au0828/au0828-video.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-417.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-video.c | 6 +++--- drivers/media/usb/em28xx/em28xx-video.c | 8 ++++---- drivers/media/usb/hdpvr/hdpvr-video.c | 4 ++-- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 4 ++-- drivers/media/usb/s2255/s2255drv.c | 8 ++++---- drivers/media/usb/stk1160/stk1160-v4l.c | 4 ++-- drivers/media/usb/tlg2300/pd-video.c | 8 ++++---- drivers/media/usb/tm6000/tm6000-video.c | 6 +++--- drivers/media/usb/usbvision/usbvision-video.c | 4 ++-- drivers/media/v4l2-core/v4l2-ioctl.c | 6 +++--- drivers/staging/media/davinci_vpfe/vpfe_video.c | 6 +++--- drivers/staging/media/dt3155v4l/dt3155v4l.c | 4 ++-- drivers/staging/media/go7007/go7007-v4l2.c | 16 ++++++++-------- drivers/staging/media/solo6x10/v4l2-enc.c | 2 +- drivers/staging/media/solo6x10/v4l2.c | 2 +- include/media/davinci/vpbe.h | 2 +- include/media/v4l2-ioctl.h | 2 +- 56 files changed, 165 insertions(+), 165 deletions(-) (limited to 'include') diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 4143d61f79b1..fe907f2e8f59 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -832,7 +832,7 @@ static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) } */ -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct saa7146_vv *vv = dev->vv_data; @@ -856,7 +856,7 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) } for (i = 0; i < dev->ext_vv_data->num_stds; i++) - if (*id & dev->ext_vv_data->stds[i].id) + if (id & dev->ext_vv_data->stds[i].id) break; if (i != dev->ext_vv_data->num_stds) { vv->standard = &dev->ext_vv_data->stds[i]; diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c index 77f9c92186f4..66c957a02ba7 100644 --- a/drivers/media/parport/pms.c +++ b/drivers/media/parport/pms.c @@ -735,12 +735,12 @@ static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std) +static int pms_s_std(struct file *file, void *fh, v4l2_std_id std) { struct pms *dev = video_drvdata(file); int ret = 0; - dev->std = *std; + dev->std = std; if (dev->std & V4L2_STD_NTSC) { pms_framerate(dev, 30); pms_secamcross(dev, 0); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 7aea24bf3a37..4b9a256f506e 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1713,7 +1713,7 @@ static void radio_enable(struct bttv *btv) } } -static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int bttv_s_std(struct file *file, void *priv, v4l2_std_id id) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -1721,14 +1721,14 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) int err = 0; for (i = 0; i < BTTV_TVNORMS; i++) - if (*id & bttv_tvnorms[i].v4l2_id) + if (id & bttv_tvnorms[i].v4l2_id) break; if (i == BTTV_TVNORMS) { err = -EINVAL; goto err; } - btv->std = *id; + btv->std = id; set_tvnorm(btv, i); err: diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 613e5ae7d5ca..67b61cf3e03a 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -1243,7 +1243,7 @@ int cx18_init_on_first_open(struct cx18 *cx) in one place. */ cx->std++; /* Force full standard initialization */ std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; - cx18_s_std(NULL, &fh, &std); + cx18_s_std(NULL, &fh, std); cx18_s_frequency(NULL, &fh, &vf); return 0; } diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 173ccd204c1f..254c50fabd73 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -637,15 +637,15 @@ static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) +int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - if ((*std & V4L2_STD_ALL) == 0) + if ((std & V4L2_STD_ALL) == 0) return -EINVAL; - if (*std == cx->std) + if (std == cx->std) return 0; if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || @@ -656,8 +656,8 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) return -EBUSY; } - cx->std = *std; - cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + cx->std = std; + cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; cx->is_50hz = !cx->is_60hz; cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); cx->cxhdl.width = 720; diff --git a/drivers/media/pci/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h index aa9b44a611d3..43433969d633 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.h +++ b/drivers/media/pci/cx18/cx18-ioctl.h @@ -26,6 +26,6 @@ u16 cx18_service2vbi(int type); void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); void cx18_set_funcs(struct video_device *vdev); -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); +int cx18_s_std(struct file *file, void *fh, v4l2_std_id std); int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int cx18_s_input(struct file *file, void *fh, unsigned int inp); diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 812ec5ff5939..6dea11a7a858 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1222,14 +1222,14 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx23885_fh *fh = file->private_data; struct cx23885_dev *dev = fh->dev; unsigned int i; for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) - if (*id & cx23885_tvnorms[i].id) + if (id & cx23885_tvnorms[i].id) break; if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; @@ -1237,7 +1237,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) /* Have the drier core notify the subdevices */ mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, *id); + cx23885_set_tvnorm(dev, id); mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 2bbda43eb00e..ed08c89adde0 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1259,13 +1259,13 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; dprintk(1, "%s()\n", __func__); mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, *tvnorms); + cx23885_set_tvnorm(dev, tvnorms); mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 75281c1530d8..93c7d576199b 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1203,7 +1203,7 @@ int cx25821_vidioc_s_priority(struct file *file, void *f, } #ifdef TUNER_FLAG -int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms) +int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { struct cx25821_fh *fh = priv; struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1218,11 +1218,11 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms) return err; } - if (dev->tvnorm == *tvnorms) + if (dev->tvnorm == tvnorms) return 0; mutex_lock(&dev->lock); - cx25821_set_tvnorm(dev, *tvnorms); + cx25821_set_tvnorm(dev, tvnorms); mutex_unlock(&dev->lock); medusa_set_videostandard(dev); diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index f0e70ffbedd4..239f63c12f33 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -135,7 +135,7 @@ extern int cx25821_vidioc_querybuf(struct file *file, void *priv, extern int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p); extern int cx25821_vidioc_s_std(struct file *file, void *priv, - v4l2_std_id *tvnorms); + v4l2_std_id tvnorms); extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i); extern int cx25821_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i); diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 486ca8d5f2a0..150bb76e7839 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -939,12 +939,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) return 0; } -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; mutex_lock(&core->lock); - cx88_set_tvnorm(core,*id); + cx88_set_tvnorm(core, id); mutex_unlock(&core->lock); return 0; } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index ede6f139b5cc..ead5be58303d 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1193,12 +1193,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) return 0; } -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; mutex_lock(&core->lock); - cx88_set_tvnorm(core,*tvnorms); + cx88_set_tvnorm(core, tvnorms); mutex_unlock(&core->lock); return 0; diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index 2928e7287da8..07b8460953b6 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -1387,7 +1387,7 @@ int ivtv_init_on_first_open(struct ivtv *itv) if (!itv->has_cx23415) write_reg_sync(0x03, IVTV_REG_DMACONTROL); - ivtv_s_std_enc(itv, &itv->tuner_std); + ivtv_s_std_enc(itv, itv->tuner_std); /* Default interrupts enabled. For the PVR350 this includes the decoder VSYNC interrupt, which is always on. It is not only used @@ -1397,7 +1397,7 @@ int ivtv_init_on_first_open(struct ivtv *itv) if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); ivtv_set_osd_alpha(itv); - ivtv_s_std_dec(itv, &itv->tuner_std); + ivtv_s_std_dec(itv, itv->tuner_std); } else { ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); } diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index 68387d4369d6..ed73edd2bcd3 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -302,7 +302,7 @@ static int ivtv_firmware_restart(struct ivtv *itv) /* Restore encoder video standard */ std = itv->std; itv->std = 0; - ivtv_s_std_enc(itv, &std); + ivtv_s_std_enc(itv, std); if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ivtv_init_mpeg_decoder(itv); @@ -310,7 +310,7 @@ static int ivtv_firmware_restart(struct ivtv *itv) /* Restore decoder video standard */ std = itv->std_out; itv->std_out = 0; - ivtv_s_std_dec(itv, &std); + ivtv_s_std_dec(itv, std); /* Restore framebuffer if active */ if (itv->ivtvfb_restore) diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 852f11e0d636..080f179070a6 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1103,10 +1103,10 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std) +void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std) { - itv->std = *std; - itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->std = std; + itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; itv->is_50hz = !itv->is_60hz; cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz); itv->cxhdl.width = 720; @@ -1122,15 +1122,15 @@ void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std) ivtv_call_all(itv, core, s_std, itv->std); } -void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) +void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std) { struct yuv_playback_info *yi = &itv->yuv_info; DEFINE_WAIT(wait); int f; /* set display standard */ - itv->std_out = *std; - itv->is_out_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->std_out = std; + itv->is_out_60hz = (std & V4L2_STD_525_60) ? 1 : 0; itv->is_out_50hz = !itv->is_out_60hz; ivtv_call_all(itv, video, s_std_output, itv->std_out); @@ -1168,14 +1168,14 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) } } -static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) +static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std) { struct ivtv *itv = fh2id(fh)->itv; - if ((*std & V4L2_STD_ALL) == 0) + if ((std & V4L2_STD_ALL) == 0) return -EINVAL; - if (*std == itv->std) + if (std == itv->std) return 0; if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h index 34c6bc132ebd..75c397756116 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.h +++ b/drivers/media/pci/ivtv/ivtv-ioctl.h @@ -27,8 +27,8 @@ u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); void ivtv_set_osd_alpha(struct ivtv *itv); int ivtv_set_speed(struct ivtv *itv, int speed); void ivtv_set_funcs(struct video_device *vdev); -void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std); -void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std); +void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std); +void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std); int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int ivtv_s_input(struct file *file, void *fh, unsigned int inp); diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 4df79c656909..66a70814004c 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -428,7 +428,7 @@ static int empress_g_chip_ident(struct file *file, void *fh, return -EINVAL; } -static int empress_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int empress_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7134_dev *dev = file->private_data; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 1e23547531b9..a6c69a4c7fbd 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1828,7 +1828,7 @@ static int saa7134_querycap(struct file *file, void *priv, return 0; } -int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id) +int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id) { unsigned long flags; unsigned int i; @@ -1849,17 +1849,17 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ } for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) + if (id == tvnorms[i].id) break; if (i == TVNORMS) for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) + if (id & tvnorms[i].id) break; if (i == TVNORMS) return -EINVAL; - if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if ((id & V4L2_STD_SECAM) && (secam[0] != '-')) { if (secam[0] == 'L' || secam[0] == 'l') { if (secam[1] == 'C' || secam[1] == 'c') fixup = V4L2_STD_SECAM_LC; @@ -1879,7 +1879,7 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ return -EINVAL; } - *id = tvnorms[i].id; + id = tvnorms[i].id; mutex_lock(&dev->lock); if (fh && res_check(fh, RESOURCE_OVERLAY)) { @@ -1901,7 +1901,7 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ } EXPORT_SYMBOL_GPL(saa7134_s_std_internal); -static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7134_fh *fh = priv; @@ -2396,7 +2396,7 @@ static int radio_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +static int radio_s_std(struct file *file, void *fh, v4l2_std_id norm) { return 0; } diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 71eefef5e324..62169dd74c6a 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -766,7 +766,7 @@ extern struct video_device saa7134_radio_template; int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); -int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id); +int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id); int saa7134_videoport_init(struct saa7134_dev *dev); void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index e7fbd036ba44..538de52b9cfd 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -211,17 +211,17 @@ static int saa7164_encoder_initialize(struct saa7164_port *port) } /* -- V4L2 --------------------------------------------------------- */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7164_encoder_fh *fh = file->private_data; struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; unsigned int i; - dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id); + dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)id); for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { - if (*id & saa7164_tvnorms[i].id) + if (id & saa7164_tvnorms[i].id) break; } if (i == ARRAY_SIZE(saa7164_tvnorms)) @@ -234,7 +234,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) */ saa7164_api_set_audio_std(port); - dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id); + dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)id); return 0; } diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index bfc8cec110de..da224eb39b95 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -183,17 +183,17 @@ static int saa7164_vbi_initialize(struct saa7164_port *port) } /* -- V4L2 --------------------------------------------------------- */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7164_vbi_fh *fh = file->private_data; struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; unsigned int i; - dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id); + dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)id); for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { - if (*id & saa7164_tvnorms[i].id) + if (id & saa7164_tvnorms[i].id) break; } if (i == ARRAY_SIZE(saa7164_tvnorms)) @@ -206,7 +206,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) */ saa7164_api_set_audio_std(port); - dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id); + dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)id); return 0; } diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 4b703fe8c953..7005695aa4bd 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -439,22 +439,22 @@ static int vidioc_querycap(struct file *file, void *priv, * * other, returned from video DAC. */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct sta2x11_vip *vip = video_drvdata(file); v4l2_std_id oldstd = vip->std, newstd; int status; - if (V4L2_STD_ALL == *std) { - v4l2_subdev_call(vip->decoder, core, s_std, *std); + if (V4L2_STD_ALL == std) { + v4l2_subdev_call(vip->decoder, core, s_std, std); ssleep(2); v4l2_subdev_call(vip->decoder, video, querystd, &newstd); v4l2_subdev_call(vip->decoder, video, g_input_status, &status); if (status & V4L2_IN_ST_NO_SIGNAL) return -EIO; - *std = vip->std = newstd; - if (oldstd != *std) { - if (V4L2_STD_525_60 & (*std)) + std = vip->std = newstd; + if (oldstd != std) { + if (V4L2_STD_525_60 & std) vip->format = formats_60[0]; else vip->format = formats_50[0]; @@ -462,14 +462,14 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } - if (oldstd != *std) { - if (V4L2_STD_525_60 & (*std)) + if (oldstd != std) { + if (V4L2_STD_525_60 & std) vip->format = formats_60[0]; else vip->format = formats_50[0]; } - return v4l2_subdev_call(vip->decoder, core, s_std, *std); + return v4l2_subdev_call(vip->decoder, core, s_std, std); } /** diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 2e8f518f298f..1168a84a737d 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -2435,14 +2435,14 @@ static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) return 0; } -static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std) +static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) { struct zoran_fh *fh = __fh; struct zoran *zr = fh->zr; int res = 0; mutex_lock(&zr->resource_lock); - res = zoran_set_norm(zr, *std); + res = zoran_set_norm(zr, std); if (res) goto sstd_unlock_and_return; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 476cfc88d144..96f6a4922d0c 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -633,7 +633,7 @@ static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std) { struct bcap_device *bcap_dev = video_drvdata(file); int ret; @@ -641,11 +641,11 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) if (vb2_is_busy(&bcap_dev->buffer_queue)) return -EBUSY; - ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std); + ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, std); if (ret < 0) return ret; - bcap_dev->std = *std; + bcap_dev->std = std; return 0; } diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 2a49f00c4543..33b9660b7f77 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -431,7 +431,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, * Sets the standard if supported by the current encoder. Return the status. * 0 - success & -EINVAL on error */ -static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; @@ -442,14 +442,14 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) V4L2_OUT_CAP_STD)) return -EINVAL; - ret = vpbe_get_std_info(vpbe_dev, *std_id); + ret = vpbe_get_std_info(vpbe_dev, std_id); if (ret) return ret; mutex_lock(&vpbe_dev->lock); ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_std_output, *std_id); + s_std_output, std_id); /* set the lcd controller output for the given mode */ if (!ret) { struct osd_state *osd_device = vpbe_dev->osd_device; @@ -513,7 +513,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, */ if (preset_mode->timings_type & VPBE_ENC_STD) return vpbe_s_std(vpbe_dev, - &preset_mode->std_id); + preset_mode->std_id); if (preset_mode->timings_type & VPBE_ENC_DV_TIMINGS) { dv_timings = diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 30976dc9f346..bcf0ada3481d 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -983,7 +983,7 @@ static int vpbe_display_try_fmt(struct file *file, void *priv, * 0 - success & -EINVAL on error */ static int vpbe_display_s_std(struct file *file, void *priv, - v4l2_std_id *std_id) + v4l2_std_id std_id) { struct vpbe_fh *fh = priv; struct vpbe_layer *layer = fh->layer; diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 3d1af6704822..20db8a077990 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -376,7 +376,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) * values in ccdc */ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, - const v4l2_std_id *std_id) + v4l2_std_id std_id) { struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; struct v4l2_mbus_framefmt mbus_fmt; @@ -384,7 +384,7 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, int i, ret = 0; for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { - if (vpfe_standards[i].std_id & *std_id) { + if (vpfe_standards[i].std_id & std_id) { vpfe_dev->std_info.active_pixels = vpfe_standards[i].width; vpfe_dev->std_info.active_lines = @@ -461,7 +461,7 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) /* Configure the default format information */ ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); + vpfe_standards[vpfe_dev->std_index].std_id); if (ret) return ret; @@ -1168,7 +1168,7 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) /* set the default image parameters in the device */ ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); + vpfe_standards[vpfe_dev->std_index].std_id); unlock_out: mutex_unlock(&vpfe_dev->lock); return ret; @@ -1193,7 +1193,7 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) return ret; } -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_subdev_info *sdinfo; @@ -1215,7 +1215,7 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) } ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_std, *std_id); + core, s_std, std_id); if (ret < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); goto unlock_out; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index d869c8e868ee..00b7f9c5ac04 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1395,7 +1395,7 @@ static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) * @priv: file handle * @std_id: ptr to std id */ -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; @@ -1424,7 +1424,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) fh->initialized = 1; /* Call encoder subdevice function to set the standard */ - ch->video.stdid = *std_id; + ch->video.stdid = std_id; memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings)); /* Get the information about the standard */ @@ -1437,7 +1437,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) vpif_config_format(ch); /* set standard in the sub device */ - ret = v4l2_subdev_call(ch->sd, core, s_std, *std_id); + ret = v4l2_subdev_call(ch->sd, core, s_std, std_id); if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); return ret; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 3bb187c9402b..f1dff9ec1ea2 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1059,14 +1059,14 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return vb2_qbuf(&common->buffer_queue, buf); } -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; int ret = 0; - if (!(*std_id & VPIF_V4L2_STD)) + if (!(std_id & VPIF_V4L2_STD)) return -EINVAL; if (common->started) { @@ -1075,7 +1075,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) } /* Call encoder subdevice function to set the standard */ - ch->video.stdid = *std_id; + ch->video.stdid = std_id; memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings)); /* Get the information about the standard */ if (vpif_update_resolution(ch)) @@ -1093,14 +1093,14 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) vpif_config_format(ch); ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_std_output, *std_id); + s_std_output, std_id); if (ret < 0) { vpif_err("Failed to set output standard\n"); return ret; } ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, - s_std, *std_id); + s_std, std_id); if (ret < 0) vpif_err("Failed to set standard for sub devices\n"); return ret; diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 5f7db3f1f6f5..3a6a0dcdc3e4 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -957,12 +957,12 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct viu_fh *fh = priv; - fh->dev->std = *id; - decoder_call(fh->dev, core, s_std, *id); + fh->dev->std = id; + decoder_call(fh->dev, core, s_std, id); return 0; } diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 92a33f081852..76a862318a7e 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1357,7 +1357,7 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) } /* from vivi.c */ -static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) +static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a) { return 0; } diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 9961e13f683d..ef0efdf422fe 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -574,7 +574,7 @@ static int mxr_dv_timings_cap(struct file *file, void *fh, return ret ? -EINVAL : 0; } -static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm) +static int mxr_s_std(struct file *file, void *fh, v4l2_std_id norm) { struct mxr_layer *layer = video_drvdata(file); struct mxr_device *mdev = layer->mdev; @@ -591,7 +591,7 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm) return -EBUSY; } - ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm); + ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, norm); mutex_unlock(&mdev->mutex); diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index d853162586fa..8e3b95a6c29e 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -881,29 +881,29 @@ static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) } } -static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct sh_vou_device *vou_dev = video_drvdata(file); int ret; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id); + dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); - if (*std_id & ~vou_dev->vdev->tvnorms) + if (std_id & ~vou_dev->vdev->tvnorms) return -EINVAL; ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_std_output, *std_id); + s_std_output, std_id); /* Shall we continue, if the subdev doesn't support .s_std_output()? */ if (ret < 0 && ret != -ENOIOCTLCMD) return ret; - if (*std_id & V4L2_STD_525_60) + if (std_id & V4L2_STD_525_60) sh_vou_reg_ab_set(vou_dev, VOUCR, sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29); else sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29); - vou_dev->std = *std_id; + vou_dev->std = std_id; return 0; } diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 8ec98051ea73..3592968026cd 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -256,12 +256,12 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) +static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id a) { struct soc_camera_device *icd = file->private_data; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, core, s_std, *a); + return v4l2_subdev_call(sd, core, s_std, a); } static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c index 2d91eeb1d2ae..a2f7bdd5104f 100644 --- a/drivers/media/platform/timblogiw.c +++ b/drivers/media/platform/timblogiw.c @@ -336,7 +336,7 @@ static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id std) { struct video_device *vdev = video_devdata(file); struct timblogiw *lw = video_get_drvdata(vdev); @@ -348,10 +348,10 @@ static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std) mutex_lock(&lw->lock); if (TIMBLOGIW_HAS_DECODER(lw)) - err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std); + err = v4l2_subdev_call(lw->sd_enc, core, s_std, std); if (!err) - fh->cur_norm = timblogiw_get_norm(*std); + fh->cur_norm = timblogiw_get_norm(std); mutex_unlock(&lw->lock); diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index b051c4a28554..a794cd6c4441 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -847,7 +847,7 @@ static int viacam_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std) +static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id std) { return 0; } diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c index eb5d6f955709..c6af974c5b45 100644 --- a/drivers/media/platform/vino.c +++ b/drivers/media/platform/vino.c @@ -3042,7 +3042,7 @@ static int vino_g_std(struct file *file, void *__fh, } static int vino_s_std(struct file *file, void *__fh, - v4l2_std_id *std) + v4l2_std_id std) { struct vino_channel_settings *vcs = video_drvdata(file); unsigned long flags; @@ -3056,7 +3056,7 @@ static int vino_s_std(struct file *file, void *__fh, } /* check if the standard is valid for the current input */ - if ((*std) & vino_inputs[vcs->input].std) { + if (std & vino_inputs[vcs->input].std) { dprintk("standard accepted\n"); /* change the video norm for SAA7191 @@ -3065,13 +3065,13 @@ static int vino_s_std(struct file *file, void *__fh, if (vcs->input == VINO_INPUT_D1) goto out; - if ((*std) & V4L2_STD_PAL) { + if (std & V4L2_STD_PAL) { ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL, &flags); - } else if ((*std) & V4L2_STD_NTSC) { + } else if (std & V4L2_STD_NTSC) { ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC, &flags); - } else if ((*std) & V4L2_STD_SECAM) { + } else if (std & V4L2_STD_SECAM) { ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM, &flags); } else { diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 11316f2f2e42..e9dd01c4b6ed 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1320,7 +1320,7 @@ out: return rc; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; @@ -1332,7 +1332,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) have to make the au0828 bridge adjust the size of its capture buffer, which is currently hardcoded at 720x480 */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm); + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm); dev->std_set_in_tuner_core = 1; if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 49c842aa1f70..f548db8043d4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1492,14 +1492,14 @@ static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx231xx_fh *fh = file->private_data; struct cx231xx *dev = fh->dev; unsigned int i; for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++) - if (*id & cx231xx_tvnorms[i].id) + if (id & cx231xx_tvnorms[i].id) break; if (i == ARRAY_SIZE(cx231xx_tvnorms)) return -EINVAL; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 53020a7e01fe..4cff2f4075e1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -987,7 +987,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -998,13 +998,13 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) if (rc < 0) return rc; - if (dev->norm == *norm) + if (dev->norm == norm) return 0; if (videobuf_queue_is_busy(&fh->vb_vidq)) return -EBUSY; - dev->norm = *norm; + dev->norm = norm; /* Adjusts width/height, if needed */ dev->width = 720; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 3ef696d36c7e..96d84c22ef00 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -996,23 +996,23 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; struct v4l2_format f; - if (*norm == dev->norm) + if (norm == dev->norm) return 0; if (dev->streaming_users > 0) return -EBUSY; - dev->norm = *norm; + dev->norm = norm; /* Adjusts width/height, if needed */ f.fmt.pix.width = 720; - f.fmt.pix.height = (*norm & V4L2_STD_525_60) ? 480 : 576; + f.fmt.pix.height = (norm & V4L2_STD_525_60) ? 480 : 576; vidioc_try_fmt_vid_cap(file, priv, &f); /* set new image size */ diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 6a15405360dc..2983bf0d5f0f 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -582,13 +582,13 @@ static int vidioc_querycap(struct file *file, void *priv, } static int vidioc_s_std(struct file *file, void *private_data, - v4l2_std_id *std) + v4l2_std_id std) { struct hdpvr_fh *fh = file->private_data; struct hdpvr_device *dev = fh->dev; u8 std_type = 1; - if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) + if (std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) std_type = 0; return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 0f729c92e3cf..a7774e3836d4 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -196,13 +196,13 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) return ret; } -static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; return pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std); + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), std); } static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 2bd86132d3e3..ab97e7d0b4f2 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1294,7 +1294,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) { struct s2255_fh *fh = priv; struct s2255_mode mode; @@ -1314,7 +1314,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) goto out_s_std; } mode = fh->channel->mode; - if (*i & V4L2_STD_525_60) { + if (i & V4L2_STD_525_60) { dprintk(4, "%s 60 Hz\n", __func__); /* if changing format, reset frame decimation/intervals */ if (mode.format != FORMAT_NTSC) { @@ -1324,7 +1324,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) channel->width = LINE_SZ_4CIFS_NTSC; channel->height = NUM_LINES_4CIFS_NTSC * 2; } - } else if (*i & V4L2_STD_625_50) { + } else if (i & V4L2_STD_625_50) { dprintk(4, "%s 50 Hz\n", __func__); if (mode.format != FORMAT_PAL) { mode.restart = 1; @@ -1337,7 +1337,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) ret = -EINVAL; goto out_s_std; } - fh->channel->std = *i; + fh->channel->std = i; if (mode.restart) s2255_set_mode(fh->channel, &mode); out_s_std: diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 5307a63e378f..f6a6cdc8b288 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -375,7 +375,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct stk1160 *dev = video_drvdata(file); struct vb2_queue *q = &dev->vb_vidq; @@ -388,7 +388,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) return -ENODEV; /* We need to set this now, before we call stk1160_set_std */ - dev->norm = *norm; + dev->norm = norm; /* This is taken from saa7115 video decoder */ if (dev->norm & V4L2_STD_525_60) { diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 9595309caed4..8df668d06552 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -801,7 +801,7 @@ static int vidioc_g_fmt_vbi(struct file *file, void *fh, return 0; } -static int set_std(struct poseidon *pd, v4l2_std_id *norm) +static int set_std(struct poseidon *pd, v4l2_std_id norm) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; @@ -811,7 +811,7 @@ static int set_std(struct poseidon *pd, v4l2_std_id *norm) int height; for (i = 0; i < POSEIDON_TVNORMS; i++) { - if (*norm & poseidon_tvnorms[i].v4l2_id) { + if (norm & poseidon_tvnorms[i].v4l2_id) { param = poseidon_tvnorms[i].tlg_tvnorm; log("name : %s", poseidon_tvnorms[i].name); goto found; @@ -846,7 +846,7 @@ out: return ret; } -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id norm) { struct front_face *front = fh; @@ -1270,7 +1270,7 @@ static int restore_v4l2_context(struct poseidon *pd, pd_video_checkmode(pd); - set_std(pd, &context->tvnormid); + set_std(pd, context->tvnormid); vidioc_s_input(NULL, front, context->sig_index); pd_vidioc_s_tuner(pd, context->audio_idx); pd_vidioc_s_fmt(pd, &context->pix); diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index b4618d7d9c4b..a78de1d1bc9e 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1056,13 +1056,13 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { int rc = 0; struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; - dev->norm = *norm; + dev->norm = norm; rc = tm6000_init_analog_mode(dev); fh->width = dev->width; @@ -1134,7 +1134,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) dev->input = i; - rc = vidioc_s_std(file, priv, &dev->vfd->current_norm); + rc = vidioc_s_std(file, priv, dev->vfd->current_norm); return rc; } diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 874cfec0b8db..041f19e1b05b 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -595,11 +595,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct usb_usbvision *usbvision = video_drvdata(file); - usbvision->tvnorm_id = *id; + usbvision->tvnorm_id = id; call_all(usbvision, core, s_std, usbvision->tvnorm_id); /* propagate the change to the decoder */ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 8ec8abe0ffe7..d80d8afba3fb 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1383,15 +1383,15 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { struct video_device *vfd = video_devdata(file); - v4l2_std_id *id = arg, norm; + v4l2_std_id id = *(v4l2_std_id *)arg, norm; int ret; - norm = (*id) & vfd->tvnorms; + norm = id & vfd->tvnorms; if (vfd->tvnorms && !norm) /* Check if std is supported */ return -EINVAL; /* Calls the specific handler */ - ret = ops->vidioc_s_std(file, fh, &norm); + ret = ops->vidioc_s_std(file, fh, norm); /* Updates standard information */ if (ret >= 0) diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 19dc5b062d07..3670a7b0724e 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -924,7 +924,7 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) * * Return 0 on success, error code otherwise */ -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpfe_video_device *video = video_drvdata(file); struct vpfe_device *vpfe_dev = video->vpfe_dev; @@ -945,13 +945,13 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) goto unlock_out; } ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_std, *std_id); + core, s_std, std_id); if (ret < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); video->stdid = V4L2_STD_UNKNOWN; goto unlock_out; } - video->stdid = *std_id; + video->stdid = std_id; unlock_out: mutex_unlock(&video->lock); return ret; diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index e33b7f55d84e..073b3b35f8f4 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -612,9 +612,9 @@ dt3155_ioc_g_std(struct file *filp, void *p, v4l2_std_id *norm) } static int -dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id *norm) +dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id norm) { - if (*norm & DT3155_CURRENT_NORM) + if (norm & DT3155_CURRENT_NORM) return 0; return -EINVAL; } diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 4e477f3b78f3..29fe94da5f71 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1117,40 +1117,40 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct go7007 *go = ((struct go7007_file *) priv)->go; if (go->streaming) return -EBUSY; - if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && *std != 0) + if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && std != 0) return -EINVAL; - if (*std == 0) + if (std == 0) return -EINVAL; if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && go->input == go->board_info->num_inputs - 1) { if (!go->i2c_adapter_online) return -EIO; - if (call_all(&go->v4l2_dev, core, s_std, *std) < 0) + if (call_all(&go->v4l2_dev, core, s_std, std) < 0) return -EINVAL; } - if (*std & V4L2_STD_NTSC) { + if (std & V4L2_STD_NTSC) { go->standard = GO7007_STD_NTSC; go->sensor_framerate = 30000; - } else if (*std & V4L2_STD_PAL) { + } else if (std & V4L2_STD_PAL) { go->standard = GO7007_STD_PAL; go->sensor_framerate = 25025; - } else if (*std & V4L2_STD_SECAM) { + } else if (std & V4L2_STD_SECAM) { go->standard = GO7007_STD_PAL; go->sensor_framerate = 25025; } else return -EINVAL; - call_all(&go->v4l2_dev, core, s_std, *std); + call_all(&go->v4l2_dev, core, s_std, std); set_capture_size(go, NULL, 0); return 0; diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 4977e869d5b7..310b126e1288 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -1326,7 +1326,7 @@ static int solo_enc_streamoff(struct file *file, void *priv, return videobuf_streamoff(&fh->vidq); } -static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i) +static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) { return 0; } diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index ca774cc57539..87f3c0452ca4 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -773,7 +773,7 @@ static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->vidq); } -static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i) +static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) { return 0; } diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index a7ca4884c46c..57585c7004a4 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -132,7 +132,7 @@ struct vpbe_device_ops { struct v4l2_enum_dv_timings *timings_info); /* Set std at the output */ - int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id std_id); /* Get the current std at the output */ int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 0da8682a0481..ee7b7c67c87a 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -132,7 +132,7 @@ struct v4l2_ioctl_ops { ENUMSTD is handled by videodev.c */ int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm); - int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm); + int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id norm); int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a); /* Input handling */ -- cgit v1.2.3 From 977ba3b1b73f24fae2d0c8bd59d7a4696f1e0ccc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 24 Mar 2013 08:28:46 -0300 Subject: [media] v4l2: add const to argument of write-only s_register ioctl This ioctl is defined as IOW, so pass the argument as const. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/au8522_decoder.c | 2 +- drivers/media/i2c/ad9389b.c | 2 +- drivers/media/i2c/adv7183.c | 2 +- drivers/media/i2c/adv7604.c | 2 +- drivers/media/i2c/ak881x.c | 2 +- drivers/media/i2c/cs5345.c | 2 +- drivers/media/i2c/cx25840/cx25840-core.c | 2 +- drivers/media/i2c/m52790.c | 2 +- drivers/media/i2c/mt9m032.c | 2 +- drivers/media/i2c/mt9v011.c | 2 +- drivers/media/i2c/ov7670.c | 2 +- drivers/media/i2c/saa7115.c | 2 +- drivers/media/i2c/saa7127.c | 2 +- drivers/media/i2c/saa717x.c | 2 +- drivers/media/i2c/soc_camera/mt9m001.c | 2 +- drivers/media/i2c/soc_camera/mt9m111.c | 2 +- drivers/media/i2c/soc_camera/mt9t031.c | 2 +- drivers/media/i2c/soc_camera/mt9t112.c | 2 +- drivers/media/i2c/soc_camera/mt9v022.c | 2 +- drivers/media/i2c/soc_camera/ov2640.c | 2 +- drivers/media/i2c/soc_camera/ov5642.c | 2 +- drivers/media/i2c/soc_camera/ov6650.c | 2 +- drivers/media/i2c/soc_camera/ov772x.c | 2 +- drivers/media/i2c/soc_camera/ov9640.c | 2 +- drivers/media/i2c/soc_camera/ov9740.c | 2 +- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 2 +- drivers/media/i2c/soc_camera/tw9910.c | 2 +- drivers/media/i2c/ths7303.c | 2 +- drivers/media/i2c/tvp5150.c | 2 +- drivers/media/i2c/tvp7002.c | 2 +- drivers/media/i2c/upd64031a.c | 2 +- drivers/media/i2c/upd64083.c | 2 +- drivers/media/i2c/vs6624.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 5 ++-- drivers/media/pci/cx18/cx18-av-core.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 36 ++++++++++--------------- drivers/media/pci/cx23885/cx23885-ioctl.c | 9 +++---- drivers/media/pci/cx23885/cx23885-ioctl.h | 2 +- drivers/media/pci/cx23885/cx23888-ir.c | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.h | 2 +- drivers/media/pci/cx88/cx88-video.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 9 ++++--- drivers/media/pci/saa7134/saa7134-video.c | 2 +- drivers/media/pci/saa7146/mxb.c | 3 +-- drivers/media/pci/saa7164/saa7164-encoder.c | 2 +- drivers/media/platform/blackfin/bfin_capture.c | 2 +- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 3 ++- drivers/media/platform/davinci/vpif_display.c | 3 ++- drivers/media/platform/marvell-ccic/mcam-core.c | 2 +- drivers/media/platform/sh_vou.c | 2 +- drivers/media/platform/soc_camera/soc_camera.c | 2 +- drivers/media/usb/au0828/au0828-video.c | 2 +- drivers/media/usb/cx231xx/cx231xx-video.c | 2 +- drivers/media/usb/cx231xx/cx231xx.h | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 2 +- drivers/media/usb/gspca/gspca.c | 2 +- drivers/media/usb/gspca/gspca.h | 8 +++--- drivers/media/usb/gspca/pac7302.c | 2 +- drivers/media/usb/gspca/sn9c20x.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-hdw.h | 2 +- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/usb/stk1160/stk1160-v4l.c | 2 +- drivers/media/usb/usbvision/usbvision-video.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- include/media/v4l2-ioctl.h | 2 +- include/media/v4l2-subdev.h | 2 +- 69 files changed, 96 insertions(+), 102 deletions(-) (limited to 'include') diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index 5243ba6295cc..526902b45f9c 100644 --- a/drivers/media/dvb-frontends/au8522_decoder.c +++ b/drivers/media/dvb-frontends/au8522_decoder.c @@ -583,7 +583,7 @@ static int au8522_g_register(struct v4l2_subdev *sd, } static int au8522_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct au8522_state *state = to_state(sd); diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index c2886b6a727d..58344b6c3a55 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -354,7 +354,7 @@ static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int ad9389b_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int ad9389b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 6fed5b74e743..56a1fa4af0fe 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -507,7 +507,7 @@ static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index f47555b1000a..31a63c9324fe 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -699,7 +699,7 @@ static int adv7604_g_register(struct v4l2_subdev *sd, } static int adv7604_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index ba674656b10d..fd47465e4f6a 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -101,7 +101,7 @@ static int ak881x_g_register(struct v4l2_subdev *sd, } static int ak881x_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c index c8581e26fa9c..1d2f7c8512b5 100644 --- a/drivers/media/i2c/cs5345.c +++ b/drivers/media/i2c/cs5345.c @@ -110,7 +110,7 @@ static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return 0; } -static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int cs5345_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 234b7c63d087..12fb9b2eb887 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1671,7 +1671,7 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c index 0991576f4c82..39f50fd2b8d2 100644 --- a/drivers/media/i2c/m52790.c +++ b/drivers/media/i2c/m52790.c @@ -96,7 +96,7 @@ static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return 0; } -static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct m52790_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index f80c1d7ec884..2526b66b91fd 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -548,7 +548,7 @@ static int mt9m032_g_register(struct v4l2_subdev *sd, } static int mt9m032_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct mt9m032 *sensor = to_mt9m032(sd); struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 73b7688cbebd..3f415fd12de3 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -421,7 +421,7 @@ static int mt9v011_g_register(struct v4l2_subdev *sd, } static int mt9v011_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 05ed5b8e7f88..617ad3fff4aa 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1487,7 +1487,7 @@ static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return ret; } -static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 6b6788cd08f6..5d9d0330b3df 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1428,7 +1428,7 @@ static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int saa711x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index b745f68fbc92..8a47ac10927f 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -672,7 +672,7 @@ static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 5608b937f8b2..cf3a0aa7e45e 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -988,7 +988,7 @@ static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); u16 addr = reg->reg & 0xffff; diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index bcdc86175549..dd9089805757 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -360,7 +360,7 @@ static int mt9m001_g_register(struct v4l2_subdev *sd, } static int mt9m001_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 2902ba633da6..8bd4e0d2ea03 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -641,7 +641,7 @@ static int mt9m111_g_register(struct v4l2_subdev *sd, } static int mt9m111_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index d80d044ebf15..26a15b87a9a2 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -430,7 +430,7 @@ static int mt9t031_g_register(struct v4l2_subdev *sd, } static int mt9t031_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 188e29b03273..a7256b732804 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -766,7 +766,7 @@ static int mt9t112_g_register(struct v4l2_subdev *sd, } static int mt9t112_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 53eaf899d3b6..a295e598486f 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -497,7 +497,7 @@ static int mt9v022_g_register(struct v4l2_subdev *sd, } static int mt9v022_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 0f520f693b6e..e3168424f9ba 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -756,7 +756,7 @@ static int ov2640_g_register(struct v4l2_subdev *sd, } static int ov2640_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 9d53309619d2..9aa56de69eed 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -708,7 +708,7 @@ static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register return ret; } -static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index dbe4f564e6b2..991202d4bbae 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -421,7 +421,7 @@ static int ov6650_get_register(struct v4l2_subdev *sd, } static int ov6650_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index fbeb5b2f3ae5..713d62e349f6 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -652,7 +652,7 @@ static int ov772x_g_register(struct v4l2_subdev *sd, } static int ov772x_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 05993041be31..20ca62d371c1 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -322,7 +322,7 @@ static int ov9640_get_register(struct v4l2_subdev *sd, } static int ov9640_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 2f236da80165..012bd6271124 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -835,7 +835,7 @@ static int ov9740_get_register(struct v4l2_subdev *sd, } static int ov9740_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 5c92679bfefb..1f9ec3b06b4e 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -1161,7 +1161,7 @@ static int rj54n1_g_register(struct v4l2_subdev *sd, } static int rj54n1_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 7d2074601881..bad90b16a6dd 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -554,7 +554,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd, } static int tw9910_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index 3ca60c7cd95f..c4339556a2ea 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -245,7 +245,7 @@ static int ths7303_g_register(struct v4l2_subdev *sd, } static int ths7303_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 5967e1a0c809..485159a3c0b7 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1067,7 +1067,7 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 7406de9b45db..027809cca5f5 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -768,7 +768,7 @@ static int tvp7002_g_register(struct v4l2_subdev *sd, * -EPERM if call not allowed. */ static int tvp7002_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c index d15cfd944e57..f0a09214c519 100644 --- a/drivers/media/i2c/upd64031a.c +++ b/drivers/media/i2c/upd64031a.c @@ -175,7 +175,7 @@ static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register return 0; } -static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c index 75d6acc62018..343e0215f74c 100644 --- a/drivers/media/i2c/upd64083.c +++ b/drivers/media/i2c/upd64083.c @@ -133,7 +133,7 @@ static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register return 0; } -static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int upd64083_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 9ac1b8c3a837..f366fad6269e 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -748,7 +748,7 @@ static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return 0; } -static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 4b9a256f506e..e33a2d2f81a8 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1945,7 +1945,7 @@ static int bttv_g_register(struct file *file, void *f, } static int bttv_s_register(struct file *file, void *f, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -1961,8 +1961,7 @@ static int bttv_s_register(struct file *file, void *f, } /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - btwrite(reg->val, reg->reg); + btwrite(reg->val, reg->reg & 0xfff); return 0; } diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index c22242bc10df..38b1d64ffc27 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -1266,7 +1266,7 @@ static int cx18_av_g_register(struct v4l2_subdev *sd, } static int cx18_av_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx18 *cx = v4l2_get_subdevdata(sd); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 254c50fabd73..7dbd5a9451ed 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -415,42 +415,34 @@ static int cx18_g_chip_ident(struct file *file, void *fh, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) -{ - struct v4l2_dbg_register *regs = arg; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) - return -EINVAL; - - regs->size = 4; - if (cmd == VIDIOC_DBG_S_REGISTER) - cx18_write_enc(cx, regs->val, regs->reg); - else - regs->val = cx18_read_enc(cx, regs->reg); - return 0; -} - static int cx18_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { struct cx18 *cx = fh2id(fh)->cx; - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); + if (v4l2_chip_match_host(®->match)) { + if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + reg->size = 4; + reg->val = cx18_read_enc(cx, reg->reg); + return 0; + } /* FIXME - errors shouldn't be ignored */ cx18_call_all(cx, core, g_register, reg); return 0; } static int cx18_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx18 *cx = fh2id(fh)->cx; - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); + if (v4l2_chip_match_host(®->match)) { + if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + cx18_write_enc(cx, reg->val, reg->reg); + return 0; + } /* FIXME - errors shouldn't be ignored */ cx18_call_all(cx, core, s_register, reg); return 0; diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index ea9a614f3bbf..acdb6d58db58 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -158,18 +158,17 @@ int cx23885_g_register(struct file *file, void *fh, } static int cx23885_s_host_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) return -EINVAL; - reg->size = 4; cx_write(reg->reg, reg->val); return 0; } static int cx23417_s_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { if (dev->v4l_device == NULL) return -EINVAL; @@ -179,13 +178,11 @@ static int cx23417_s_register(struct cx23885_dev *dev, if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val)) return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ - - reg->size = 4; return 0; } int cx23885_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h index 315be0ca5a04..a6080964a9ee 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.h +++ b/drivers/media/pci/cx23885/cx23885-ioctl.h @@ -33,7 +33,7 @@ int cx23885_g_register(struct file *file, void *fh, int cx23885_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); #endif #endif diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index d51eed051d59..fa672fe41079 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -1124,7 +1124,7 @@ static int cx23888_ir_g_register(struct v4l2_subdev *sd, } static int cx23888_ir_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx23888_ir_state *state = to_state(sd); u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 93c7d576199b..1465591d000c 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1364,7 +1364,7 @@ int cx25821_vidioc_g_register(struct file *file, void *fh, } int cx25821_vidioc_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 239f63c12f33..11ba5eb93677 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -155,7 +155,7 @@ extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, extern int cx25821_vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg); extern int cx25821_vidioc_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index ead5be58303d..e3f6181d1044 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1380,7 +1380,7 @@ static int vidioc_g_register (struct file *file, void *fh, } static int vidioc_s_register (struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 861e4629c7fc..50379b26768b 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -748,12 +748,15 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register return 0; } -static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { struct ivtv *itv = fh2id(fh)->itv; - if (v4l2_chip_match_host(®->match)) - return ivtv_itvc(itv, false, reg->reg, ®->val); + if (v4l2_chip_match_host(®->match)) { + u64 val = reg->val; + + return ivtv_itvc(itv, false, reg->reg, &val); + } /* TODO: subdev errors should not be ignored, this should become a subdev helper function. */ ivtv_call_all(itv, core, s_register, reg); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index a6c69a4c7fbd..1363e97ccda4 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2300,7 +2300,7 @@ static int vidioc_g_register (struct file *file, void *priv, } static int vidioc_s_register (struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 9dd044b563e7..71e8bead321b 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -680,7 +680,7 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist return 0; } -static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; @@ -688,7 +688,6 @@ static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_regist return -EPERM; if (v4l2_chip_match_host(®->match)) { saa7146_write(dev, reg->reg, reg->val); - reg->size = 4; return 0; } return call_all(dev, core, s_register, reg); diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 538de52b9cfd..0b74fb2300dd 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -1313,7 +1313,7 @@ static int saa7164_g_register(struct file *file, void *fh, } static int saa7164_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; struct saa7164_dev *dev = port->dev; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 96f6a4922d0c..0e55b087076f 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -890,7 +890,7 @@ static int bcap_dbg_g_register(struct file *file, void *priv, } static int bcap_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct bcap_device *bcap_dev = video_drvdata(file); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index bcf0ada3481d..1802f11e939f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1597,7 +1597,7 @@ static int vpbe_display_g_register(struct file *file, void *priv, } static int vpbe_display_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { return 0; } diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 00b7f9c5ac04..5f98df1fc8a0 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1924,7 +1924,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv, * Returns zero or -EINVAL if write operations fails. */ static int vpif_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ + const struct v4l2_dbg_register *reg) +{ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index f1dff9ec1ea2..1b3fb5ca2ad4 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1568,7 +1568,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv, * Returns zero or -EINVAL if write operations fails. */ static int vpif_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ + const struct v4l2_dbg_register *reg) +{ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 76a862318a7e..64ab91edfb81 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1445,7 +1445,7 @@ static int mcam_vidioc_g_register(struct file *file, void *priv, } static int mcam_vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct mcam_camera *cam = priv; diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 8e3b95a6c29e..7d0235069c87 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -1266,7 +1266,7 @@ static int sh_vou_g_register(struct file *file, void *fh, } static int sh_vou_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct sh_vou_device *vou_dev = video_drvdata(file); diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 3592968026cd..bf55abfb7cbc 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1042,7 +1042,7 @@ static int soc_camera_g_register(struct file *file, void *fh, } static int soc_camera_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct soc_camera_device *icd = file->private_data; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index e9dd01c4b6ed..79f1d510cc2e 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1754,7 +1754,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 4cff2f4075e1..cd221474e1b9 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1404,7 +1404,7 @@ int cx231xx_g_register(struct file *file, void *priv, } int cx231xx_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 2f9faee539cb..5ad9fd61d3c8 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -949,7 +949,7 @@ int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident int cx231xx_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg); int cx231xx_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); /* Provided by cx231xx-cards.c */ extern void cx231xx_pre_card_setup(struct cx231xx *dev); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 96d84c22ef00..d09b5c03c723 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1323,7 +1323,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 924e032461d0..5995ec4de6bc 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1039,7 +1039,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct gspca_dev *gspca_dev = video_drvdata(file); diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index c3af3212d51e..ef8efeb80070 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -74,8 +74,10 @@ typedef int (*cam_get_jpg_op) (struct gspca_dev *, struct v4l2_jpegcompression *); typedef int (*cam_set_jpg_op) (struct gspca_dev *, const struct v4l2_jpegcompression *); -typedef int (*cam_reg_op) (struct gspca_dev *, +typedef int (*cam_get_reg_op) (struct gspca_dev *, struct v4l2_dbg_register *); +typedef int (*cam_set_reg_op) (struct gspca_dev *, + const struct v4l2_dbg_register *); typedef int (*cam_ident_op) (struct gspca_dev *, struct v4l2_dbg_chip_ident *); typedef void (*cam_streamparm_op) (struct gspca_dev *, @@ -108,8 +110,8 @@ struct sd_desc { cam_streamparm_op get_streamparm; cam_streamparm_op set_streamparm; #ifdef CONFIG_VIDEO_ADV_DEBUG - cam_reg_op set_register; - cam_reg_op get_register; + cam_set_reg_op set_register; + cam_get_reg_op get_register; #endif cam_ident_op get_chip_ident; #if IS_ENABLED(CONFIG_INPUT) diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index 682ef3340911..6008c8d546a3 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -840,7 +840,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, #ifdef CONFIG_VIDEO_ADV_DEBUG static int sd_dbg_s_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { u8 index; u8 value; diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index 4ec544f4a845..ead9a1f58513 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -1598,7 +1598,7 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev, } static int sd_dbg_s_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct sd *sd = (struct sd *) gspca_dev; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 299751a8b06b..e11267f35d87 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -5165,7 +5165,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) int pvr2_hdw_register_access(struct pvr2_hdw *hdw, - struct v4l2_dbg_match *match, u64 reg_id, + const struct v4l2_dbg_match *match, u64 reg_id, int setFl, u64 *val_ptr) { #ifdef CONFIG_VIDEO_ADV_DEBUG diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h index 8060fc666eeb..91bae930cd79 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h @@ -240,7 +240,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *, setFl - true to set the register, false to read it val_ptr - storage location for source / result. */ int pvr2_hdw_register_access(struct pvr2_hdw *, - struct v4l2_dbg_match *match, u64 reg_id, + const struct v4l2_dbg_match *match, u64 reg_id, int setFl, u64 *val_ptr); /* The following entry points are all lower level things you normally don't diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index a7774e3836d4..a8a65fa57930 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -815,7 +815,7 @@ static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_regist return ret; } -static int pvr2_s_register(struct file *file, void *priv, struct v4l2_dbg_register *req) +static int pvr2_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *req) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index f6a6cdc8b288..c4c723b92f6e 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -500,7 +500,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct stk1160 *dev = video_drvdata(file); diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 041f19e1b05b..d34c2afe2c24 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -483,7 +483,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct usb_usbvision *usbvision = video_drvdata(file); int err_code; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 29c751d86061..936ca25bd5be 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1813,7 +1813,7 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG - struct v4l2_dbg_register *p = arg; + const struct v4l2_dbg_register *p = arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index ee7b7c67c87a..a4175cda4fc1 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -242,7 +242,7 @@ struct v4l2_ioctl_ops { int (*vidioc_g_register) (struct file *file, void *fh, struct v4l2_dbg_register *reg); int (*vidioc_s_register) (struct file *file, void *fh, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); #endif int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 79784fc8f9e9..8158a0810fdc 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -165,7 +165,7 @@ struct v4l2_subdev_core_ops { long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); #ifdef CONFIG_VIDEO_ADV_DEBUG int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); - int (*s_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); + int (*s_register)(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg); #endif int (*s_power)(struct v4l2_subdev *sd, int on); int (*interrupt_service_routine)(struct v4l2_subdev *sd, -- cgit v1.2.3 From 6cd247ef22e493e1884e576c066661538b031981 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 9 Mar 2013 05:55:11 -0300 Subject: [media] v4l2-ctrls: eliminate lockdep false alarms for struct v4l2_ctrl_handler.lock When calling v4l2_ctrl_add_handler(), lockdep would detect a potential recursive locking problem on a situation that is by design intended and not a recursive lock. This happened because all struct v4l2_ctrl_handler.lock mutexes were created as members of the same lock class in v4l2_ctrl_handler_init(), and v4l2_ctrl_add_handler() takes the hdl->lock on two different v4l2_ctrl_handler instances. This change breaks the large lockdep lock class for struct v4l2_ctrl_handler.lock and breaks it into v4l2_ctrl_handler instantiation specific lock classes with meaningful class names. This will validly eliminate lockdep alarms for v4l2_ctrl_handler locking validation, as long as the relationships between drivers adding v4l2 controls to their own handler from other v4l2 drivers' control handlers remains straightforward. struct v4l2_ctrl_handler.lock lock classes are created with names such that the output of cat /proc/lockdep indicates where in the v4l2 driver code v4l2_ctrl_handle_init() is being called on instantiations: ffffffffa045f490 FD: 10 BD: 8 +.+...: cx2341x:1534:(hdl)->lock ffffffffa0497d20 FD: 12 BD: 2 +.+.+.: saa7115:1581:(hdl)->lock ffffffffa04ac660 FD: 14 BD: 2 +.+.+.: msp3400_driver:756:(hdl)->lock ffffffffa0484b90 FD: 12 BD: 1 +.+.+.: ivtv_gpio:366:(&itv->hdl_gpio)->lock ffffffffa04eb530 FD: 11 BD: 2 +.+.+.: cx25840_core:1982:(&state->hdl)->lock ffffffffa04fbc80 FD: 11 BD: 3 +.+.+.: wm8775:246:(&state->hdl)->lock Some lock chains, that were previously causing the recursion alarms, are now visible in the output of cat /proc/lockdep_chains: irq_context: 0 [ffffffffa0497d20] saa7115:1581:(hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa04ac660] msp3400_driver:756:(hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa0484b90] ivtv_gpio:366:(&itv->hdl_gpio)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa04eb530] cx25840_core:1982:(&state->hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa04fbc80] wm8775:246:(&state->hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock Signed-off-by: Andy Walls [hans.verkuil@cisco.com: keep mutex_init in v4l2_ctrl_handler_init_class] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 8 +++++--- include/media/v4l2-ctrls.h | 29 ++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 6b28b5800500..b36d1ec13ee6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1362,11 +1362,13 @@ static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err) } /* Initialize the handler */ -int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, - unsigned nr_of_controls_hint) +int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, + unsigned nr_of_controls_hint, + struct lock_class_key *key, const char *name) { hdl->lock = &hdl->_lock; mutex_init(hdl->lock); + lockdep_set_class_and_name(hdl->lock, key, name); INIT_LIST_HEAD(&hdl->ctrls); INIT_LIST_HEAD(&hdl->ctrl_refs); hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; @@ -1375,7 +1377,7 @@ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, hdl->error = hdl->buckets ? 0 : -ENOMEM; return hdl->error; } -EXPORT_SYMBOL(v4l2_ctrl_handler_init); +EXPORT_SYMBOL(v4l2_ctrl_handler_init_class); /* Free all controls and control refs */ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index f00d42bc01a6..7343a27fe819 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -259,7 +259,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags); -/** v4l2_ctrl_handler_init() - Initialize the control handler. +/** v4l2_ctrl_handler_init_class() - Initialize the control handler. * @hdl: The control handler. * @nr_of_controls_hint: A hint of how many controls this handler is * expected to refer to. This is the total number, so including @@ -268,12 +268,35 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, * are allocated) or the control lookup becomes slower (not enough * buckets are allocated, so there are more slow list lookups). * It will always work, though. + * @key: Used by the lock validator if CONFIG_LOCKDEP is set. + * @name: Used by the lock validator if CONFIG_LOCKDEP is set. * * Returns an error if the buckets could not be allocated. This error will * also be stored in @hdl->error. + * + * Never use this call directly, always use the v4l2_ctrl_handler_init + * macro that hides the @key and @name arguments. */ -int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, - unsigned nr_of_controls_hint); +int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, + unsigned nr_of_controls_hint, + struct lock_class_key *key, const char *name); + +#ifdef CONFIG_LOCKDEP +#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint) \ +( \ + ({ \ + static struct lock_class_key _key; \ + v4l2_ctrl_handler_init_class(hdl, nr_of_controls_hint, \ + &_key, \ + KBUILD_BASENAME ":" \ + __stringify(__LINE__) ":" \ + "(" #hdl ")->_lock"); \ + }) \ +) +#else +#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint) \ + v4l2_ctrl_handler_init_class(hdl, nr_of_controls_hint, NULL, NULL) +#endif /** v4l2_ctrl_handler_free() - Free all controls owned by the handler and free * the control list. -- cgit v1.2.3 From 2180f92def1921397f422f278b3cc65751b749cc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 3 Mar 2013 20:12:31 -0300 Subject: [media] v4l2-core: add code to check for specific ops This patch adds a v4l2_subdev_has_op() macro and a v4l2_device_has_op macro to quickly check if a specific subdev or any subdev supports a particular subdev operation. This makes it easy for drivers to disable certain ioctls if none of the subdevs supports the necessary functionality. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-device.h | 13 +++++++++++++ include/media/v4l2-subdev.h | 3 +++ 2 files changed, 16 insertions(+) (limited to 'include') diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index d61febfb1668..c9b1593923f6 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -190,4 +190,17 @@ v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev); ##args); \ }) +#define v4l2_device_has_op(v4l2_dev, o, f) \ +({ \ + struct v4l2_subdev *__sd; \ + bool __result = false; \ + list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ + if (v4l2_subdev_has_op(__sd, o, f)) { \ + __result = true; \ + break; \ + } \ + } \ + __result; \ +}) + #endif diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 8158a0810fdc..c42703a37602 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -687,4 +687,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, ((!(sd) || !(sd)->v4l2_dev || !(sd)->v4l2_dev->notify) ? -ENODEV : \ (sd)->v4l2_dev->notify((sd), (notification), (arg))) +#define v4l2_subdev_has_op(sd, o, f) \ + ((sd)->ops->o && (sd)->ops->o->f) + #endif -- cgit v1.2.3 From 9ca5470cc1433200698a43de2d6e683815e536e6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 10:34:04 -0300 Subject: [media] v4l2-ctrls: add V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER control Control whether video sequence headers should be repeated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 6 ++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 2 ++ include/uapi/linux/v4l2-controls.h | 1 + 3 files changed, 9 insertions(+) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 9e8f85498678..b4952e23201b 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -2299,6 +2299,12 @@ Possible values are: + + V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER  + boolean + Repeat the video sequence headers. Repeating these +headers makes random access to the video stream easier. Applicable to the MPEG1, 2 and 4 encoder. + V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER  boolean diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index b36d1ec13ee6..f662df3bfe2d 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -695,6 +695,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; + case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header"; /* CAMERA controls */ /* Keep the order of the 'case's the same as in videodev2.h! */ @@ -844,6 +845,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: + case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: case V4L2_CID_WIDE_DYNAMIC_RANGE: case V4L2_CID_IMAGE_STABILIZATION: *type = V4L2_CTRL_TYPE_BOOLEAN; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7eab0b91827b..844dc0205037 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -360,6 +360,7 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) #define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) #define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_BASE+225) +#define V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER (V4L2_CID_MPEG_BASE+226) #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) -- cgit v1.2.3 From a0fc58868bbf34d0935947cdf1bc8c0ea32c68c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Mar 2013 11:22:03 -0300 Subject: [media] saa7115: add config flag to change the IDQ polarity Needed by the go7007 driver: it assumes a different polarity of the IDQ signal, so we need to be able to tell the saa7115 about this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa7115.c | 6 ++++++ include/media/saa7115.h | 31 +++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 5d9d0330b3df..c3e7e12e006a 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1259,6 +1259,12 @@ static int saa711x_s_routing(struct v4l2_subdev *sd, (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) | (state->output & 0x01)); } + if (state->ident > V4L2_IDENT_SAA7111A) { + if (config & SAA7115_IDQ_IS_DEFAULT) + saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x20); + else + saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x21); + } return 0; } diff --git a/include/media/saa7115.h b/include/media/saa7115.h index bab212719591..8b2ecc69a702 100644 --- a/include/media/saa7115.h +++ b/include/media/saa7115.h @@ -21,6 +21,8 @@ #ifndef _SAA7115_H_ #define _SAA7115_H_ +/* s_routing inputs, outputs, and config */ + /* SAA7111/3/4/5 HW inputs */ #define SAA7115_COMPOSITE0 0 #define SAA7115_COMPOSITE1 1 @@ -33,24 +35,33 @@ #define SAA7115_SVIDEO2 8 #define SAA7115_SVIDEO3 9 -/* SAA7115 v4l2_crystal_freq frequency values */ -#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */ -#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */ - -/* SAA7115 v4l2_crystal_freq audio clock control flags */ -#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ -#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ -#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ - +/* outputs */ #define SAA7115_IPORT_ON 1 #define SAA7115_IPORT_OFF 0 -/* SAA7111 specific output flags */ +/* SAA7111 specific outputs. */ #define SAA7111_VBI_BYPASS 2 #define SAA7111_FMT_YUV422 0x00 #define SAA7111_FMT_RGB 0x40 #define SAA7111_FMT_CCIR 0x80 #define SAA7111_FMT_YUV411 0xc0 +/* config flags */ +/* Register 0x85 should set bit 0 to 0 (it's 1 by default). This bit + * controls the IDQ signal polarity which is set to 'inverted' if the bit + * it 1 and to 'default' if it is 0. */ +#define SAA7115_IDQ_IS_DEFAULT (1 << 0) + +/* s_crystal_freq values and flags */ + +/* SAA7115 v4l2_crystal_freq frequency values */ +#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */ +#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */ + +/* SAA7115 v4l2_crystal_freq audio clock control flags */ +#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ +#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ +#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ + #endif -- cgit v1.2.3 From 1589037f8716a605a36ee6dda6f7cdd4d043522b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 03:47:25 -0300 Subject: [media] saa7115: add support for double-rate ASCLK Some devices expect a double rate ASCLK. Add a flag to let the driver know through the s_crystal_freq call. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa7115.c | 16 +++++++++++----- include/media/saa7115.h | 7 ++++--- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index cdff1f6e8546..52c717d977c9 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -83,9 +83,10 @@ struct saa711x_state { u32 ident; u32 audclk_freq; u32 crystal_freq; - u8 ucgc; + bool ucgc; u8 cgcdiv; - u8 apll; + bool apll; + bool double_asclk; }; static inline struct saa711x_state *to_state(struct v4l2_subdev *sd) @@ -732,8 +733,12 @@ static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq) if (state->apll) acc |= 0x08; + if (state->double_asclk) { + acpf <<= 1; + acni <<= 1; + } saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03); - saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10); + saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10 << state->double_asclk); saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc); saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff); @@ -1302,9 +1307,10 @@ static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags) if (freq != SAA7115_FREQ_32_11_MHZ && freq != SAA7115_FREQ_24_576_MHZ) return -EINVAL; state->crystal_freq = freq; + state->double_asclk = flags & SAA7115_FREQ_FL_DOUBLE_ASCLK; state->cgcdiv = (flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4; - state->ucgc = (flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0; - state->apll = (flags & SAA7115_FREQ_FL_APLL) ? 1 : 0; + state->ucgc = flags & SAA7115_FREQ_FL_UCGC; + state->apll = flags & SAA7115_FREQ_FL_APLL; saa711x_s_clock_freq(sd, state->audclk_freq); return 0; } diff --git a/include/media/saa7115.h b/include/media/saa7115.h index 8b2ecc69a702..407918625c80 100644 --- a/include/media/saa7115.h +++ b/include/media/saa7115.h @@ -59,9 +59,10 @@ #define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */ /* SAA7115 v4l2_crystal_freq audio clock control flags */ -#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ -#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ -#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ +#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ +#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ +#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ +#define SAA7115_FREQ_FL_DOUBLE_ASCLK (1 << 3) /* SA 39, LRDIV, SAA7114/5 only */ #endif -- cgit v1.2.3 From e4d2a6162d2a0a27be16b75da36f6bba64af63bc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 13:14:32 -0300 Subject: [media] tuner: add Sony BTF tuners This adds support for three Sony BTF tuners: TUNER_SONY_BTF_PG472Z: PAL+SECAM TUNER_SONY_BTF_PK467Z: NTSC-M-JP TUNER_SONY_BTF_PB463Z: NTSC-M These come from the go7007 staging driver where they were implemented in the wis-sony-tuner i2c driver. Adding support for these tuners to tuner-types.c is the first step towards removing the wis-sony-tuner driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 3 ++ drivers/media/tuners/tuner-types.c | 69 ++++++++++++++++++++++++++++++ drivers/staging/media/go7007/go7007-usb.c | 1 + drivers/staging/media/go7007/go7007-v4l2.c | 1 + drivers/staging/media/go7007/wis-i2c.h | 6 --- include/media/tuner.h | 4 ++ 6 files changed, 78 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index c83f6e418879..5b83a3ff15c2 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -86,3 +86,6 @@ tuner=85 - Philips FQ1236 MK5 tuner=86 - Tena TNF5337 MFD tuner=87 - Xceive 4000 tuner tuner=88 - Xceive 5000C tuner +tuner=89 - Sony PAL+SECAM (BTF-PG472Z) +tuner=90 - Sony NTSC-M-JP (BTF-PK467Z) +tuner=91 - Sony NTSC-M (BTF-PB463Z) diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c index 2da4440c16ee..98bc15a388be 100644 --- a/drivers/media/tuners/tuner-types.c +++ b/drivers/media/tuners/tuner-types.c @@ -1381,6 +1381,58 @@ static struct tuner_params tuner_philips_fq1236_mk5_params[] = { }, }; +/* --------- Sony BTF-PG472Z PAL/SECAM ------- */ + +static struct tuner_range tuner_sony_btf_pg472z_ranges[] = { + { 16 * 144.25 /*MHz*/, 0xc6, 0x01, }, + { 16 * 427.25 /*MHz*/, 0xc6, 0x02, }, + { 16 * 999.99 , 0xc6, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pg472z_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_sony_btf_pg472z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pg472z_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_invert_for_secam_lc = 1, + }, +}; + +/* 90-99 */ +/* --------- Sony BTF-PG467Z NTSC-M-JP ------- */ + +static struct tuner_range tuner_sony_btf_pg467z_ranges[] = { + { 16 * 220.25 /*MHz*/, 0xc6, 0x01, }, + { 16 * 467.25 /*MHz*/, 0xc6, 0x02, }, + { 16 * 999.99 , 0xc6, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pg467z_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sony_btf_pg467z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pg467z_ranges), + }, +}; + +/* --------- Sony BTF-PG463Z NTSC-M ------- */ + +static struct tuner_range tuner_sony_btf_pg463z_ranges[] = { + { 16 * 130.25 /*MHz*/, 0xc6, 0x01, }, + { 16 * 364.25 /*MHz*/, 0xc6, 0x02, }, + { 16 * 999.99 , 0xc6, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pg463z_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sony_btf_pg463z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pg463z_ranges), + }, +}; + /* --------------------------------------------------------------------- */ struct tunertype tuners[] = { @@ -1872,6 +1924,23 @@ struct tunertype tuners[] = { .name = "Xceive 5000C tuner", /* see xc5000.c for details */ }, + [TUNER_SONY_BTF_PG472Z] = { + .name = "Sony BTF-PG472Z PAL/SECAM", + .params = tuner_sony_btf_pg472z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pg472z_params), + }, + + /* 90-99 */ + [TUNER_SONY_BTF_PK467Z] = { + .name = "Sony BTF-PK467Z NTSC-M-JP", + .params = tuner_sony_btf_pg467z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pg467z_params), + }, + [TUNER_SONY_BTF_PB463Z] = { + .name = "Sony BTF-PB463Z NTSC-M", + .params = tuner_sony_btf_pg463z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pg463z_params), + }, }; EXPORT_SYMBOL(tuners); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 914b247e9652..3333a8f3b654 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "go7007-priv.h" #include "wis-i2c.h" diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 29fe94da5f71..4ad383ad8758 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1238,6 +1238,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (!go->i2c_adapter_online) return -EIO; + strlcpy(t->name, "Tuner", sizeof(t->name)); return call_all(&go->v4l2_dev, tuner, g_tuner, t); } diff --git a/drivers/staging/media/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h index 6d09c06c8560..97763db80bac 100644 --- a/drivers/staging/media/go7007/wis-i2c.h +++ b/drivers/staging/media/go7007/wis-i2c.h @@ -34,9 +34,3 @@ struct video_decoder_resolution { #define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution) #define DECODER_SET_CHANNEL _IOW('d', 201, int) - -/* Sony tuner types */ - -#define TUNER_SONY_BTF_PG472Z 200 -#define TUNER_SONY_BTF_PK467Z 201 -#define TUNER_SONY_BTF_PB463Z 202 diff --git a/include/media/tuner.h b/include/media/tuner.h index 926aff9bdf65..24eaafe461bd 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -138,6 +138,10 @@ #define TUNER_XC4000 87 /* Xceive Silicon Tuner */ #define TUNER_XC5000C 88 /* Xceive Silicon Tuner */ +#define TUNER_SONY_BTF_PG472Z 89 /* PAL+SECAM */ +#define TUNER_SONY_BTF_PK467Z 90 /* NTSC_JP */ +#define TUNER_SONY_BTF_PB463Z 91 /* NTSC */ + /* tv card specific */ #define TDA9887_PRESENT (1<<0) #define TDA9887_PORT1_INACTIVE (1<<1) -- cgit v1.2.3 From 73d9f979335e9ae40f3901d38af739bc36d008c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 07:20:12 -0300 Subject: [media] uda1342: add new uda1342 audio codec driver This based on the wis-uda1342.c driver that's part of the go7007 driver. It has been converted to a v4l subdev driver by Pete Eberlein, and I made additional cleanups. Based on work by: Pete Eberlein Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 9 ++++ drivers/media/i2c/Makefile | 1 + drivers/media/i2c/uda1342.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ include/media/uda1342.h | 29 ++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 drivers/media/i2c/uda1342.c create mode 100644 include/media/uda1342.h (limited to 'include') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 790788597bad..5df353f7c552 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -112,6 +112,15 @@ config VIDEO_TLV320AIC23B To compile this driver as a module, choose M here: the module will be called tlv320aic23b. +config VIDEO_UDA1342 + tristate "Philips UDA1342 audio codec" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips UDA1342 audio codec. + + To compile this driver as a module, choose M here: the + module will be called uda1342. + config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index adf950406a94..b1775b3fad04 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_M52790) += m52790.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o +obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o diff --git a/drivers/media/i2c/uda1342.c b/drivers/media/i2c/uda1342.c new file mode 100644 index 000000000000..3af408556d27 --- /dev/null +++ b/drivers/media/i2c/uda1342.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int write_reg(struct i2c_client *client, int reg, int value) +{ + /* UDA1342 wants MSB first, but SMBus sends LSB first */ + i2c_smbus_write_word_data(client, reg, swab16(value)); + return 0; +} + +static int uda1342_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + switch (input) { + case UDA1342_IN1: + write_reg(client, 0x00, 0x1241); /* select input 1 */ + break; + case UDA1342_IN2: + write_reg(client, 0x00, 0x1441); /* select input 2 */ + break; + default: + v4l2_err(sd, "input %d not supported\n", input); + break; + } + return 0; +} + +static const struct v4l2_subdev_audio_ops uda1342_audio_ops = { + .s_routing = uda1342_s_routing, +}; + +static const struct v4l2_subdev_ops uda1342_ops = { + .audio = &uda1342_audio_ops, +}; + +static int uda1342_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct v4l2_subdev *sd; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + dev_dbg(&client->dev, "initializing UDA1342 at address %d on %s\n", + client->addr, adapter->name); + + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (sd == NULL) + return -ENOMEM; + + v4l2_i2c_subdev_init(sd, client, &uda1342_ops); + + write_reg(client, 0x00, 0x8000); /* reset registers */ + write_reg(client, 0x00, 0x1241); /* select input 1 */ + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + return 0; +} + +static int uda1342_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(sd); + return 0; +} + +static const struct i2c_device_id uda1342_id[] = { + { "uda1342", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, uda1342_id); + +static struct i2c_driver uda1342_driver = { + .driver = { + .name = "uda1342", + }, + .probe = uda1342_probe, + .remove = uda1342_remove, + .id_table = uda1342_id, +}; + +module_i2c_driver(uda1342_driver); + +MODULE_LICENSE("GPL v2"); diff --git a/include/media/uda1342.h b/include/media/uda1342.h new file mode 100644 index 000000000000..cd156403a368 --- /dev/null +++ b/include/media/uda1342.h @@ -0,0 +1,29 @@ +/* + * uda1342.h - definition for uda1342 inputs + * + * Copyright 2013 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 _UDA1342_H_ +#define _UDA1342_H_ + +/* The UDA1342 has 2 inputs */ + +#define UDA1342_IN1 1 +#define UDA1342_IN2 2 + +#endif -- cgit v1.2.3 From 2d80647b6ebd2db6ef1df5e4e3319afd8867580c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:18:04 -0300 Subject: [media] v4l2-common: remove obsolete v4l_fill_dv_preset_info It's no longer used, so it can now be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 47 ----------------------------------- include/media/v4l2-common.h | 1 - 2 files changed, 48 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index aa044f491666..b81f274e60b0 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -550,53 +550,6 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, } EXPORT_SYMBOL_GPL(v4l_bound_align_image); -/** - * v4l_fill_dv_preset_info - fill description of a digital video preset - * @preset - preset value - * @info - pointer to struct v4l2_dv_enum_preset - * - * drivers can use this helper function to fill description of dv preset - * in info. - */ -int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info) -{ - static const struct v4l2_dv_preset_info { - u16 width; - u16 height; - const char *name; - } dv_presets[] = { - { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */ - { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */ - { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */ - { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */ - { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */ - { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */ - { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */ - { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */ - { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */ - { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */ - { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */ - { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */ - { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */ - { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */ - { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */ - { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */ - { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */ - { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */ - { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */ - }; - - if (info == NULL || preset >= ARRAY_SIZE(dv_presets)) - return -EINVAL; - - info->preset = preset; - info->width = dv_presets[preset].width; - info->height = dv_presets[preset].height; - strlcpy(info->name, dv_presets[preset].name, sizeof(info->name)); - return 0; -} -EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info); - /** * v4l_match_dv_timings - check if two timings match * @t1 - compare this v4l2_dv_timings struct... diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index ec7c9c00b256..1d93c48cb371 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -201,7 +201,6 @@ void v4l_bound_align_image(unsigned int *w, unsigned int wmin, unsigned int *h, unsigned int hmin, unsigned int hmax, unsigned int halign, unsigned int salign); -int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info); struct v4l2_discrete_probe { const struct v4l2_frmsize_discrete *sizes; -- cgit v1.2.3 From 6c2afac434f00267c484239ad9210c1a075e7f16 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:19:33 -0300 Subject: [media] v4l2-subdev: remove obsolete dv_preset ops These ops are no longer used, so it's time to remove them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'include') diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index c42703a37602..5298d678d0f3 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -279,14 +279,6 @@ struct v4l2_mbus_frame_desc { s_routing: see s_routing in audio_ops, except this version is for video devices. - s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to - s_std() - - g_dv_preset: get current dv (Digital Video) preset in the sub device. - - query_dv_preset: query dv preset in the sub device. This is similar to - querystd() - s_dv_timings(): Set custom dv timings in the sub device. This is used when sub device is capable of setting detailed timing information in the hardware to generate/detect the video signal. @@ -331,14 +323,6 @@ struct v4l2_subdev_video_ops { struct v4l2_subdev_frame_interval *interval); int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize); int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival); - int (*enum_dv_presets) (struct v4l2_subdev *sd, - struct v4l2_dv_enum_preset *preset); - int (*s_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); - int (*g_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); - int (*query_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); int (*s_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); int (*g_dv_timings)(struct v4l2_subdev *sd, -- cgit v1.2.3 From 02fa628217e995bd7b1fe8c1b7cc7a510f6b8349 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:21:06 -0300 Subject: [media] v4l2 core: remove the obsolete dv_preset support These ioctls are no longer used by any drivers, so remove them. [mchehab@redhat.com: Fix merge conflict] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ---- drivers/media/v4l2-core/v4l2-dev.c | 4 ---- drivers/media/v4l2-core/v4l2-ioctl.c | 32 ++------------------------- include/media/v4l2-ioctl.h | 9 -------- 4 files changed, 2 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 7157af301b14..f1295519f285 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1076,10 +1076,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_G_CHIP_IDENT: case VIDIOC_S_HW_FREQ_SEEK: - case VIDIOC_ENUM_DV_PRESETS: - case VIDIOC_S_DV_PRESET: - case VIDIOC_G_DV_PRESET: - case VIDIOC_QUERY_DV_PRESET: case VIDIOC_S_DV_TIMINGS: case VIDIOC_G_DV_TIMINGS: case VIDIOC_DQEVENT: diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index de1e9ab7db99..1fbd95755e75 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -685,7 +685,6 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio); SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio); SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio); - SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset); SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); } if (is_tx) { @@ -708,9 +707,6 @@ static void determine_valid_ioctls(struct video_device *vdev) (ops->vidioc_g_std || vdev->current_norm))) set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); - SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets); - SET_VALID_IOCTL(ops, VIDIOC_S_DV_PRESET, vidioc_s_dv_preset); - SET_VALID_IOCTL(ops, VIDIOC_G_DV_PRESET, vidioc_g_dv_preset); SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 72c22fde2b69..83aa39dfe07c 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -652,22 +652,6 @@ static void v4l_print_dbg_register(const void *arg, bool write_only) p->reg, p->val); } -static void v4l_print_dv_enum_presets(const void *arg, bool write_only) -{ - const struct v4l2_dv_enum_preset *p = arg; - - pr_cont("index=%u, preset=%u, name=%.*s, width=%u, height=%u\n", - p->index, p->preset, - (int)sizeof(p->name), p->name, p->width, p->height); -} - -static void v4l_print_dv_preset(const void *arg, bool write_only) -{ - const struct v4l2_dv_preset *p = arg; - - pr_cont("preset=%u\n", p->preset); -} - static void v4l_print_dv_timings(const void *arg, bool write_only) { const struct v4l2_dv_timings *p = arg; @@ -1011,17 +995,13 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, struct v4l2_input *p = arg; /* - * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS & + * We set the flags for CAP_DV_TIMINGS & * CAP_STD here based on ioctl handler provided by the * driver. If the driver doesn't support these * for a specific input, it must override these flags. */ if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_IN_CAP_STD; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET)) - p->capabilities |= V4L2_IN_CAP_PRESETS; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS)) - p->capabilities |= V4L2_IN_CAP_DV_TIMINGS; return ops->vidioc_enum_input(file, fh, p); } @@ -1033,17 +1013,13 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, struct v4l2_output *p = arg; /* - * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS & + * We set the flags for CAP_DV_TIMINGS & * CAP_STD here based on ioctl handler provided by the * driver. If the driver doesn't support these * for a specific output, it must override these flags. */ if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_OUT_CAP_STD; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET)) - p->capabilities |= V4L2_OUT_CAP_PRESETS; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS)) - p->capabilities |= V4L2_OUT_CAP_DV_TIMINGS; return ops->vidioc_enum_output(file, fh, p); } @@ -2040,10 +2016,6 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0), IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0), IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO), - IOCTL_INFO_STD(VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets, v4l_print_dv_enum_presets, 0), - IOCTL_INFO_STD(VIDIOC_S_DV_PRESET, vidioc_s_dv_preset, v4l_print_dv_preset, INFO_FL_PRIO), - IOCTL_INFO_STD(VIDIOC_G_DV_PRESET, vidioc_g_dv_preset, v4l_print_dv_preset, 0), - IOCTL_INFO_STD(VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset, v4l_print_dv_preset, 0), IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO), IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0), IOCTL_INFO_FNC(VIDIOC_DQEVENT, v4l_dqevent, v4l_print_event, 0), diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index a4175cda4fc1..e10c2432f902 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -254,15 +254,6 @@ struct v4l2_ioctl_ops { struct v4l2_frmivalenum *fival); /* DV Timings IOCTLs */ - int (*vidioc_enum_dv_presets) (struct file *file, void *fh, - struct v4l2_dv_enum_preset *preset); - - int (*vidioc_s_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *preset); - int (*vidioc_g_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *preset); - int (*vidioc_query_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *qpreset); int (*vidioc_s_dv_timings) (struct file *file, void *fh, struct v4l2_dv_timings *timings); int (*vidioc_g_dv_timings) (struct file *file, void *fh, -- cgit v1.2.3 From 81b8cd9284945a323009482418c3d80de1d59d25 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:22:56 -0300 Subject: [media] videodev2.h: remove obsolete DV_PRESET API This API is now obsolete and can be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 54 ------------------------------------------ 1 file changed, 54 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index b5f5cddcf1c3..9d57dba27412 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -981,52 +981,6 @@ struct v4l2_standard { __u32 reserved[4]; }; -/* The DV Preset API is deprecated in favor of the DV Timings API. - New drivers shouldn't use this anymore! */ - -/* - * V I D E O T I M I N G S D V P R E S E T - */ -struct v4l2_dv_preset { - __u32 preset; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T S E N U M E R A T I O N - */ -struct v4l2_dv_enum_preset { - __u32 index; - __u32 preset; - __u8 name[32]; /* Name of the preset timing */ - __u32 width; - __u32 height; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T V A L U E S - */ -#define V4L2_DV_INVALID 0 -#define V4L2_DV_480P59_94 1 /* BT.1362 */ -#define V4L2_DV_576P50 2 /* BT.1362 */ -#define V4L2_DV_720P24 3 /* SMPTE 296M */ -#define V4L2_DV_720P25 4 /* SMPTE 296M */ -#define V4L2_DV_720P30 5 /* SMPTE 296M */ -#define V4L2_DV_720P50 6 /* SMPTE 296M */ -#define V4L2_DV_720P59_94 7 /* SMPTE 274M */ -#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ -#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I25 11 /* BT.1120 */ -#define V4L2_DV_1080I50 12 /* SMPTE 296M */ -#define V4L2_DV_1080I60 13 /* SMPTE 296M */ -#define V4L2_DV_1080P24 14 /* SMPTE 296M */ -#define V4L2_DV_1080P25 15 /* SMPTE 296M */ -#define V4L2_DV_1080P30 16 /* SMPTE 296M */ -#define V4L2_DV_1080P50 17 /* BT.1120 */ -#define V4L2_DV_1080P60 18 /* BT.1120 */ - /* * D V B T T I M I N G S */ @@ -1240,7 +1194,6 @@ struct v4l2_input { #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ /* capabilities flags */ -#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ #define V4L2_IN_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_IN_CAP_CUSTOM_TIMINGS V4L2_IN_CAP_DV_TIMINGS /* For compatibility */ #define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ @@ -1264,7 +1217,6 @@ struct v4l2_output { #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 /* capabilities flags */ -#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ #define V4L2_OUT_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_OUT_CAP_CUSTOM_TIMINGS V4L2_OUT_CAP_DV_TIMINGS /* For compatibility */ #define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ @@ -1981,12 +1933,6 @@ struct v4l2_create_buffers { #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) -/* These four DV Preset ioctls are deprecated in favor of the DV Timings - ioctls. */ -#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) -#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) -#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) -#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) #define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) -- cgit v1.2.3 From 79b0c6400517456935f84f8d46c8bb0cf73f1813 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 12:16:34 -0300 Subject: [media] v4l2: add new VIDIOC_DBG_G_CHIP_NAME ioctl Simplify the debugging ioctls by creating the VIDIOC_DBG_G_CHIP_NAME ioctl. This will eventually replace VIDIOC_DBG_G_CHIP_IDENT. Chip matching is done by the name or index of subdevices or an index to a bridge chip. Most of this can all be done automatically, so most drivers just need to provide get/set register ops. In particular, it is now possible to get/set subdev registers without requiring assistance of the bridge driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 5 +- drivers/media/v4l2-core/v4l2-dev.c | 5 +- drivers/media/v4l2-core/v4l2-ioctl.c | 115 ++++++++++++++++++++++++++++++++-- include/media/v4l2-ioctl.h | 3 + include/uapi/linux/videodev2.h | 34 +++++++--- 5 files changed, 146 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index a9e7703560ad..f8fac9cefc3c 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -230,7 +230,7 @@ EXPORT_SYMBOL(v4l2_ctrl_next); int v4l2_chip_match_host(const struct v4l2_dbg_match *match) { switch (match->type) { - case V4L2_CHIP_MATCH_HOST: + case V4L2_CHIP_MATCH_BRIDGE: return match->addr == 0; default: return 0; @@ -254,6 +254,9 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match return len && !strncmp(c->driver->driver.name, match->name, len); case V4L2_CHIP_MATCH_I2C_ADDR: return c->addr == match->addr; + case V4L2_CHIP_MATCH_SUBDEV_IDX: + case V4L2_CHIP_MATCH_SUBDEV_NAME: + return 1; default: return 0; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 1fbd95755e75..670b9ca8ecbe 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -591,9 +591,10 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); + set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); #ifdef CONFIG_VIDEO_ADV_DEBUG - SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register); - SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register); + set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); #endif SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident); /* yes, really vidioc_subscribe_event */ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 83aa39dfe07c..336ed2dd607c 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -629,7 +629,8 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) const struct v4l2_dbg_chip_ident *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -638,12 +639,27 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) p->ident, p->revision); } +static void v4l_print_dbg_chip_name(const void *arg, bool write_only) +{ + const struct v4l2_dbg_chip_name *p = arg; + + pr_cont("type=%u, ", p->match.type); + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + pr_cont("name=%.*s, ", + (int)sizeof(p->match.name), p->match.name); + else + pr_cont("addr=%u, ", p->match.addr); + pr_cont("name=%.*s\n", (int)sizeof(p->name), p->name); +} + static void v4l_print_dbg_register(const void *arg, bool write_only) { const struct v4l2_dbg_register *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -1775,15 +1791,38 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, return ret; } +static bool v4l_dbg_found_match(const struct v4l2_dbg_match *match, + struct v4l2_subdev *sd, int idx) +{ + if (match->type == V4L2_CHIP_MATCH_SUBDEV_IDX) + return match->addr == idx; + return !strcmp(match->name, sd->name); +} + static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct v4l2_dbg_register *p = arg; + struct video_device *vfd = video_devdata(file); + struct v4l2_subdev *sd; + int idx = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return ops->vidioc_g_register(file, fh, p); + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (vfd->v4l2_dev == NULL) + return -EINVAL; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, idx++)) + return v4l2_subdev_call(sd, core, g_register, p); + } + return -EINVAL; + } + if (ops->vidioc_g_register) + return ops->vidioc_g_register(file, fh, p); + return -EINVAL; #else return -ENOTTY; #endif @@ -1794,10 +1833,25 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, { #ifdef CONFIG_VIDEO_ADV_DEBUG const struct v4l2_dbg_register *p = arg; + struct video_device *vfd = video_devdata(file); + struct v4l2_subdev *sd; + int idx = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return ops->vidioc_s_register(file, fh, p); + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (vfd->v4l2_dev == NULL) + return -EINVAL; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, idx++)) + return v4l2_subdev_call(sd, core, s_register, p); + } + return -EINVAL; + } + if (ops->vidioc_s_register) + return ops->vidioc_s_register(file, fh, p); + return -EINVAL; #else return -ENOTTY; #endif @@ -1810,9 +1864,61 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, p->ident = V4L2_IDENT_NONE; p->revision = 0; + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX) + return -EINVAL; return ops->vidioc_g_chip_ident(file, fh, p); } +static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_dbg_chip_name *p = arg; + struct v4l2_subdev *sd; + int idx = 0; + + switch (p->match.type) { + case V4L2_CHIP_MATCH_BRIDGE: +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (ops->vidioc_s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (ops->vidioc_g_register) + p->flags |= V4L2_CHIP_FL_READABLE; +#endif + if (ops->vidioc_g_chip_name) + return ops->vidioc_g_chip_name(file, fh, arg); + if (p->match.addr) + return -EINVAL; + if (vfd->v4l2_dev) + strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); + else if (vfd->parent) + strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name)); + else + strlcpy(p->name, "bridge", sizeof(p->name)); + return 0; + + case V4L2_CHIP_MATCH_SUBDEV_IDX: + case V4L2_CHIP_MATCH_SUBDEV_NAME: + if (vfd->v4l2_dev == NULL) + break; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, idx++)) { +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (sd->ops->core && sd->ops->core->s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (sd->ops->core && sd->ops->core->g_register) + p->flags |= V4L2_CHIP_FL_READABLE; +#endif + strlcpy(p->name, sd->name, sizeof(p->name)); + return 0; + } + } + break; + } + return -EINVAL; +} + static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -2027,6 +2133,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0), IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), + IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_NAME, v4l_dbg_g_chip_name, v4l_print_dbg_chip_name, INFO_FL_CLEAR(v4l2_dbg_chip_name, match)), }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index e10c2432f902..75a7dfc07dec 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -247,6 +247,9 @@ struct v4l2_ioctl_ops { int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip); + int (*vidioc_g_chip_name) (struct file *file, void *fh, + struct v4l2_dbg_chip_name *chip); + int (*vidioc_enum_framesizes) (struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 9d57dba27412..e9c49c5e6416 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1807,10 +1807,13 @@ struct v4l2_event_subscription { /* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */ -#define V4L2_CHIP_MATCH_HOST 0 /* Match against chip ID on host (0 for the host) */ -#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ -#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ -#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ +#define V4L2_CHIP_MATCH_BRIDGE 0 /* Match against chip ID on the bridge (0 for the bridge) */ +#define V4L2_CHIP_MATCH_HOST V4L2_CHIP_MATCH_BRIDGE +#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ +#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ +#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ +#define V4L2_CHIP_MATCH_SUBDEV_NAME 4 /* Match against subdev name */ +#define V4L2_CHIP_MATCH_SUBDEV_IDX 5 /* Match against subdev index */ struct v4l2_dbg_match { __u32 type; /* Match type */ @@ -1834,6 +1837,17 @@ struct v4l2_dbg_chip_ident { __u32 revision; /* chip revision, chip specific */ } __attribute__ ((packed)); +#define V4L2_CHIP_FL_READABLE (1 << 0) +#define V4L2_CHIP_FL_WRITABLE (1 << 1) + +/* VIDIOC_DBG_G_CHIP_NAME */ +struct v4l2_dbg_chip_name { + struct v4l2_dbg_match match; + char name[32]; + __u32 flags; + __u32 reserved[8]; +} __attribute__ ((packed)); + /** * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument * @index: on return, index of the first created buffer @@ -1911,15 +1925,12 @@ struct v4l2_create_buffers { #define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls) #define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls) #define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls) -#if 1 #define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum) #define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum) #define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx) #define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) #define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) -#endif -#if 1 /* Experimental, meant for debugging, testing and internal use. Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. You must be root to use these ioctls. Never use these in applications! */ @@ -1927,9 +1938,10 @@ struct v4l2_create_buffers { #define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) /* Experimental, meant for debugging, testing and internal use. - Never use this ioctl in applications! */ + Never use this ioctl in applications! + Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_NAME and + will go away in the future. */ #define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) -#endif #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) @@ -1963,6 +1975,10 @@ struct v4l2_create_buffers { versions. */ #define VIDIOC_ENUM_FREQ_BANDS _IOWR('V', 101, struct v4l2_frequency_band) +/* Experimental, meant for debugging, testing and internal use. + Never use these in applications! */ +#define VIDIOC_DBG_G_CHIP_NAME _IOWR('V', 102, struct v4l2_dbg_chip_name) + /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ -- cgit v1.2.3 From 6d43be7789db0455a82a3ad4ff5f713cc588c1e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Mar 2013 08:04:52 -0300 Subject: [media] ioctl numbers are unsigned int ioctl's number is unsigned int. Fix it at vidioc_default. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-ioctl.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 2 +- drivers/media/pci/meye/meye.c | 2 +- drivers/media/platform/davinci/vpfe_capture.c | 2 +- drivers/media/radio/radio-si4713.c | 2 +- drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 2 +- include/media/v4l2-ioctl.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 7dbd5a9451ed..aee7b6dacbfe 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -1110,7 +1110,7 @@ static int cx18_log_status(struct file *file, void *fh) } static long cx18_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) + unsigned int cmd, void *arg) { struct cx18 *cx = fh2id(fh)->cx; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 50379b26768b..9cbbce0eaedc 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1807,7 +1807,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) } static long ivtv_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) + unsigned int cmd, void *arg) { struct ivtv *itv = fh2id(fh)->itv; diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 7859c43479d7..2381b05432e6 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1410,7 +1410,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) } static long vidioc_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) + unsigned int cmd, void *arg) { switch (cmd) { case MEYEIOC_G_PARAMS: diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 20db8a077990..8c50d3074866 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1686,7 +1686,7 @@ unlock_out: static long vpfe_param_handler(struct file *file, void *priv, - bool valid_prio, int cmd, void *param) + bool valid_prio, unsigned int cmd, void *param) { struct vpfe_device *vpfe_dev = video_drvdata(file); int ret = 0; diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 2a2d21ed9133..38b3f1541c4e 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -222,7 +222,7 @@ static int radio_si4713_s_frequency(struct file *file, void *p, } static long radio_si4713_default(struct file *file, void *p, - bool valid_prio, int cmd, void *arg) + bool valid_prio, unsigned int cmd, void *arg) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, ioctl, cmd, arg); diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c index 39a8fb2802e4..6c7d20f8f67c 100644 --- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c @@ -1021,7 +1021,7 @@ static int solo_s_parm(struct file *file, void *priv, } static long solo_enc_default(struct file *file, void *fh, - bool valid_prio, int cmd, void *arg) + bool valid_prio, unsigned int cmd, void *arg) { struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 75a7dfc07dec..b273f0e81818 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -275,7 +275,7 @@ struct v4l2_ioctl_ops { /* For other private ioctls */ long (*vidioc_default) (struct file *file, void *fh, - bool valid_prio, int cmd, void *arg); + bool valid_prio, unsigned int cmd, void *arg); }; -- cgit v1.2.3 From 3f8ec5df11aa2ad7402cfb3368532a96b63426a4 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:21 -0300 Subject: [media] mfd: Add header files and Kbuild plumbing for SI476x MFD core This patch adds all necessary header files and Kbuild plumbing for the core driver for Silicon Laboratories Si476x series of AM/FM tuner chips. The driver as a whole is implemented as an MFD device and this patch adds a core portion of it that provides all the necessary functionality to the two other drivers that represent radio and audio codec subsystems of the chip. Acked-by: Hans Verkuil Acked-by: Sam Ravnborg Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- drivers/mfd/Kconfig | 12 + drivers/mfd/Makefile | 4 + include/linux/mfd/si476x-core.h | 525 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 541 insertions(+) create mode 100644 include/linux/mfd/si476x-core.h (limited to 'include') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 671f5b171c73..9b80e1edeeb6 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -976,6 +976,18 @@ config MFD_WL1273_CORE driver connects the radio-wl1273 V4L2 module and the wl1273 audio codec. +config MFD_SI476X_CORE + tristate "Support for Silicon Laboratories 4761/64/68 AM/FM radio." + depends on I2C + select MFD_CORE + help + This is the core driver for the SI476x series of AM/FM + radio. This MFD driver connects the radio-si476x V4L2 module + and the si476x audio codec. + + To compile this driver as a module, choose M here: the + module will be called si476x-core. + config MFD_OMAP_USB_HOST bool "Support OMAP USBHS core and TLL driver" depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b90409c23664..b7aaa1e104a1 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -131,6 +131,10 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o + +si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o +obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o + obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o diff --git a/include/linux/mfd/si476x-core.h b/include/linux/mfd/si476x-core.h new file mode 100644 index 000000000000..2136b2631dc3 --- /dev/null +++ b/include/linux/mfd/si476x-core.h @@ -0,0 +1,525 @@ +/* + * include/media/si476x-core.h -- Common definitions for si476x core + * device + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 SI476X_CORE_H +#define SI476X_CORE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Command Timeouts */ +#define SI476X_DEFAULT_TIMEOUT 100000 +#define SI476X_TIMEOUT_TUNE 700000 +#define SI476X_TIMEOUT_POWER_UP 330000 +#define SI476X_STATUS_POLL_US 0 + +/* -------------------- si476x-i2c.c ----------------------- */ + +enum si476x_freq_supported_chips { + SI476X_CHIP_SI4761 = 1, + SI476X_CHIP_SI4764, + SI476X_CHIP_SI4768, +}; + +enum si476x_mfd_cells { + SI476X_RADIO_CELL = 0, + SI476X_CODEC_CELL, + SI476X_MFD_CELLS, +}; + +/** + * enum si476x_power_state - possible power state of the si476x + * device. + * + * @SI476X_POWER_DOWN: In this state all regulators are turned off + * and the reset line is pulled low. The device is completely + * inactive. + * @SI476X_POWER_UP_FULL: In this state all the power regualtors are + * turned on, reset line pulled high, IRQ line is enabled(polling is + * active for polling use scenario) and device is turned on with + * POWER_UP command. The device is ready to be used. + * @SI476X_POWER_INCONSISTENT: This state indicates that previous + * power down was inconsistent, meaning some of the regulators were + * not turned down and thus use of the device, without power-cycling + * is impossible. + */ +enum si476x_power_state { + SI476X_POWER_DOWN = 0, + SI476X_POWER_UP_FULL = 1, + SI476X_POWER_INCONSISTENT = 2, +}; + +/** + * struct si476x_core - internal data structure representing the + * underlying "core" device which all the MFD cell-devices use. + * + * @client: Actual I2C client used to transfer commands to the chip. + * @chip_id: Last digit of the chip model(E.g. "1" for SI4761) + * @cells: MFD cell devices created by this driver. + * @cmd_lock: Mutex used to serialize all the requests to the core + * device. This filed should not be used directly. Instead + * si476x_core_lock()/si476x_core_unlock() should be used to get + * exclusive access to the "core" device. + * @users: Active users counter(Used by the radio cell) + * @rds_read_queue: Wait queue used to wait for RDS data. + * @rds_fifo: FIFO in which all the RDS data received from the chip is + * placed. + * @rds_fifo_drainer: Worker that drains on-chip RDS FIFO. + * @rds_drainer_is_working: Flag used for launching only one instance + * of the @rds_fifo_drainer. + * @rds_drainer_status_lock: Lock used to guard access to the + * @rds_drainer_is_working variable. + * @command: Wait queue for wainting on the command comapletion. + * @cts: Clear To Send flag set upon receiving first status with CTS + * set. + * @tuning: Wait queue used for wainting for tune/seek comand + * completion. + * @stc: Similar to @cts, but for the STC bit of the status value. + * @power_up_parameters: Parameters used as argument for POWER_UP + * command when the device is started. + * @state: Current power state of the device. + * @supplues: Structure containing handles to all power supplies used + * by the device (NULL ones are ignored). + * @gpio_reset: GPIO pin connectet to the RSTB pin of the chip. + * @pinmux: Chip's configurable pins configuration. + * @diversity_mode: Chips role when functioning in diversity mode. + * @status_monitor: Polling worker used in polling use case scenarion + * (when IRQ is not avalible). + * @revision: Chip's running firmware revision number(Used for correct + * command set support). + */ + +struct si476x_core { + struct i2c_client *client; + struct regmap *regmap; + int chip_id; + struct mfd_cell cells[SI476X_MFD_CELLS]; + + struct mutex cmd_lock; /* for serializing fm radio operations */ + atomic_t users; + + wait_queue_head_t rds_read_queue; + struct kfifo rds_fifo; + struct work_struct rds_fifo_drainer; + bool rds_drainer_is_working; + struct mutex rds_drainer_status_lock; + + wait_queue_head_t command; + atomic_t cts; + + wait_queue_head_t tuning; + atomic_t stc; + + struct si476x_power_up_args power_up_parameters; + + enum si476x_power_state power_state; + + struct regulator_bulk_data supplies[4]; + + int gpio_reset; + + struct si476x_pinmux pinmux; + enum si476x_phase_diversity_mode diversity_mode; + + atomic_t is_alive; + + struct delayed_work status_monitor; +#define SI476X_WORK_TO_CORE(w) container_of(to_delayed_work(w), \ + struct si476x_core, \ + status_monitor) + + int revision; + + int rds_fifo_depth; +}; + +static inline struct si476x_core *i2c_mfd_cell_to_core(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + return i2c_get_clientdata(client); +} + + +/** + * si476x_core_lock() - lock the core device to get an exclusive access + * to it. + */ +static inline void si476x_core_lock(struct si476x_core *core) +{ + mutex_lock(&core->cmd_lock); +} + +/** + * si476x_core_unlock() - unlock the core device to relinquish an + * exclusive access to it. + */ +static inline void si476x_core_unlock(struct si476x_core *core) +{ + mutex_unlock(&core->cmd_lock); +} + +/* *_TUNE_FREQ family of commands accept frequency in multiples of + 10kHz */ +static inline u16 hz_to_si476x(struct si476x_core *core, int freq) +{ + u16 result; + + switch (core->power_up_parameters.func) { + default: + case SI476X_FUNC_FM_RECEIVER: + result = freq / 10000; + break; + case SI476X_FUNC_AM_RECEIVER: + result = freq / 1000; + break; + } + + return result; +} + +static inline int si476x_to_hz(struct si476x_core *core, u16 freq) +{ + int result; + + switch (core->power_up_parameters.func) { + default: + case SI476X_FUNC_FM_RECEIVER: + result = freq * 10000; + break; + case SI476X_FUNC_AM_RECEIVER: + result = freq * 1000; + break; + } + + return result; +} + +/* Since the V4L2_TUNER_CAP_LOW flag is supplied, V4L2 subsystem + * mesures frequency in 62.5 Hz units */ + +static inline int hz_to_v4l2(int freq) +{ + return (freq * 10) / 625; +} + +static inline int v4l2_to_hz(int freq) +{ + return (freq * 625) / 10; +} + +static inline u16 v4l2_to_si476x(struct si476x_core *core, int freq) +{ + return hz_to_si476x(core, v4l2_to_hz(freq)); +} + +static inline int si476x_to_v4l2(struct si476x_core *core, u16 freq) +{ + return hz_to_v4l2(si476x_to_hz(core, freq)); +} + + + +/** + * struct si476x_func_info - structure containing result of the + * FUNC_INFO command. + * + * @firmware.major: Firmware major number. + * @firmware.minor[...]: Firmware minor numbers. + * @patch_id: + * @func: Mode tuner is working in. + */ +struct si476x_func_info { + struct { + u8 major, minor[2]; + } firmware; + u16 patch_id; + enum si476x_func func; +}; + +/** + * struct si476x_power_down_args - structure used to pass parameters + * to POWER_DOWN command + * + * @xosc: true - Power down, but leav oscillator running. + * false - Full power down. + */ +struct si476x_power_down_args { + bool xosc; +}; + +/** + * enum si476x_tunemode - enum representing possible tune modes for + * the chip. + * @SI476X_TM_VALIDATED_NORMAL_TUNE: Unconditionally stay on the new + * channel after tune, tune status is valid. + * @SI476X_TM_INVALIDATED_FAST_TUNE: Unconditionally stay in the new + * channel after tune, tune status invalid. + * @SI476X_TM_VALIDATED_AF_TUNE: Jump back to previous channel if + * metric thresholds are not met. + * @SI476X_TM_VALIDATED_AF_CHECK: Unconditionally jump back to the + * previous channel. + */ +enum si476x_tunemode { + SI476X_TM_VALIDATED_NORMAL_TUNE = 0, + SI476X_TM_INVALIDATED_FAST_TUNE = 1, + SI476X_TM_VALIDATED_AF_TUNE = 2, + SI476X_TM_VALIDATED_AF_CHECK = 3, +}; + +/** + * enum si476x_smoothmetrics - enum containing the possible setting fo + * audio transitioning of the chip + * @SI476X_SM_INITIALIZE_AUDIO: Initialize audio state to match this + * new channel + * @SI476X_SM_TRANSITION_AUDIO: Transition audio state from previous + * channel values to the new values + */ +enum si476x_smoothmetrics { + SI476X_SM_INITIALIZE_AUDIO = 0, + SI476X_SM_TRANSITION_AUDIO = 1, +}; + +/** + * struct si476x_rds_status_report - the structure representing the + * response to 'FM_RD_STATUS' command + * @rdstpptyint: Traffic program flag(TP) and/or program type(PTY) + * code has changed. + * @rdspiint: Program indentifiaction(PI) code has changed. + * @rdssyncint: RDS synchronization has changed. + * @rdsfifoint: RDS was received and the RDS FIFO has at least + * 'FM_RDS_INTERRUPT_FIFO_COUNT' elements in it. + * @tpptyvalid: TP flag and PTY code are valid falg. + * @pivalid: PI code is valid flag. + * @rdssync: RDS is currently synchronized. + * @rdsfifolost: On or more RDS groups have been lost/discarded flag. + * @tp: Current channel's TP flag. + * @pty: Current channel's PTY code. + * @pi: Current channel's PI code. + * @rdsfifoused: Number of blocks remaining in the RDS FIFO (0 if + * empty). + */ +struct si476x_rds_status_report { + bool rdstpptyint, rdspiint, rdssyncint, rdsfifoint; + bool tpptyvalid, pivalid, rdssync, rdsfifolost; + bool tp; + + u8 pty; + u16 pi; + + u8 rdsfifoused; + u8 ble[4]; + + struct v4l2_rds_data rds[4]; +}; + +struct si476x_rsq_status_args { + bool primary; + bool rsqack; + bool attune; + bool cancel; + bool stcack; +}; + +enum si476x_injside { + SI476X_INJSIDE_AUTO = 0, + SI476X_INJSIDE_LOW = 1, + SI476X_INJSIDE_HIGH = 2, +}; + +struct si476x_tune_freq_args { + bool zifsr; + bool hd; + enum si476x_injside injside; + int freq; + enum si476x_tunemode tunemode; + enum si476x_smoothmetrics smoothmetrics; + int antcap; +}; + +int si476x_core_stop(struct si476x_core *, bool); +int si476x_core_start(struct si476x_core *, bool); +int si476x_core_set_power_state(struct si476x_core *, enum si476x_power_state); +bool si476x_core_has_am(struct si476x_core *); +bool si476x_core_has_diversity(struct si476x_core *); +bool si476x_core_is_a_secondary_tuner(struct si476x_core *); +bool si476x_core_is_a_primary_tuner(struct si476x_core *); +bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core); +bool si476x_core_is_powered_up(struct si476x_core *core); + +enum si476x_i2c_type { + SI476X_I2C_SEND, + SI476X_I2C_RECV +}; + +int si476x_core_i2c_xfer(struct si476x_core *, + enum si476x_i2c_type, + char *, int); + + +/* -------------------- si476x-cmd.c ----------------------- */ + +int si476x_core_cmd_func_info(struct si476x_core *, struct si476x_func_info *); +int si476x_core_cmd_set_property(struct si476x_core *, u16, u16); +int si476x_core_cmd_get_property(struct si476x_core *, u16); +int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *, + enum si476x_dclk_config, + enum si476x_dfs_config, + enum si476x_dout_config, + enum si476x_xout_config); +int si476x_core_cmd_zif_pin_cfg(struct si476x_core *, + enum si476x_iqclk_config, + enum si476x_iqfs_config, + enum si476x_iout_config, + enum si476x_qout_config); +int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *, + enum si476x_icin_config, + enum si476x_icip_config, + enum si476x_icon_config, + enum si476x_icop_config); +int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *, + enum si476x_lrout_config); +int si476x_core_cmd_intb_pin_cfg(struct si476x_core *, enum si476x_intb_config, + enum si476x_a1_config); +int si476x_core_cmd_fm_seek_start(struct si476x_core *, bool, bool); +int si476x_core_cmd_am_seek_start(struct si476x_core *, bool, bool); +int si476x_core_cmd_fm_rds_status(struct si476x_core *, bool, bool, bool, + struct si476x_rds_status_report *); +int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *, bool, + struct si476x_rds_blockcount_report *); +int si476x_core_cmd_fm_tune_freq(struct si476x_core *, + struct si476x_tune_freq_args *); +int si476x_core_cmd_am_tune_freq(struct si476x_core *, + struct si476x_tune_freq_args *); +int si476x_core_cmd_am_rsq_status(struct si476x_core *, + struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); +int si476x_core_cmd_fm_rsq_status(struct si476x_core *, + struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); +int si476x_core_cmd_power_up(struct si476x_core *, + struct si476x_power_up_args *); +int si476x_core_cmd_power_down(struct si476x_core *, + struct si476x_power_down_args *); +int si476x_core_cmd_fm_phase_div_status(struct si476x_core *); +int si476x_core_cmd_fm_phase_diversity(struct si476x_core *, + enum si476x_phase_diversity_mode); + +int si476x_core_cmd_fm_acf_status(struct si476x_core *, + struct si476x_acf_status_report *); +int si476x_core_cmd_am_acf_status(struct si476x_core *, + struct si476x_acf_status_report *); +int si476x_core_cmd_agc_status(struct si476x_core *, + struct si476x_agc_status_report *); + +enum si476x_power_grid_type { + SI476X_POWER_GRID_50HZ = 0, + SI476X_POWER_GRID_60HZ, +}; + +/* Properties */ + +enum si476x_interrupt_flags { + SI476X_STCIEN = (1 << 0), + SI476X_ACFIEN = (1 << 1), + SI476X_RDSIEN = (1 << 2), + SI476X_RSQIEN = (1 << 3), + + SI476X_ERRIEN = (1 << 6), + SI476X_CTSIEN = (1 << 7), + + SI476X_STCREP = (1 << 8), + SI476X_ACFREP = (1 << 9), + SI476X_RDSREP = (1 << 10), + SI476X_RSQREP = (1 << 11), +}; + +enum si476x_rdsint_sources { + SI476X_RDSTPPTY = (1 << 4), + SI476X_RDSPI = (1 << 3), + SI476X_RDSSYNC = (1 << 1), + SI476X_RDSRECV = (1 << 0), +}; + +enum si476x_status_response_bits { + SI476X_CTS = (1 << 7), + SI476X_ERR = (1 << 6), + /* Status response for WB receiver */ + SI476X_WB_ASQ_INT = (1 << 4), + SI476X_RSQ_INT = (1 << 3), + /* Status response for FM receiver */ + SI476X_FM_RDS_INT = (1 << 2), + SI476X_ACF_INT = (1 << 1), + SI476X_STC_INT = (1 << 0), +}; + +/* -------------------- si476x-prop.c ----------------------- */ + +enum si476x_common_receiver_properties { + SI476X_PROP_INT_CTL_ENABLE = 0x0000, + SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE = 0x0200, + SI476X_PROP_DIGITAL_IO_INPUT_FORMAT = 0x0201, + SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, + SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, + + SI476X_PROP_SEEK_BAND_BOTTOM = 0x1100, + SI476X_PROP_SEEK_BAND_TOP = 0x1101, + SI476X_PROP_SEEK_FREQUENCY_SPACING = 0x1102, + + SI476X_PROP_VALID_MAX_TUNE_ERROR = 0x2000, + SI476X_PROP_VALID_SNR_THRESHOLD = 0x2003, + SI476X_PROP_VALID_RSSI_THRESHOLD = 0x2004, +}; + +enum si476x_am_receiver_properties { + SI476X_PROP_AUDIO_PWR_LINE_FILTER = 0x0303, +}; + +enum si476x_fm_receiver_properties { + SI476X_PROP_AUDIO_DEEMPHASIS = 0x0302, + + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE = 0x4000, + SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT = 0x4001, + SI476X_PROP_FM_RDS_CONFIG = 0x4002, +}; + +enum si476x_prop_audio_pwr_line_filter_bits { + SI476X_PROP_PWR_HARMONICS_MASK = 0b0000000000011111, + SI476X_PROP_PWR_GRID_MASK = 0b0000000100000000, + SI476X_PROP_PWR_ENABLE_MASK = 0b0000001000000000, + SI476X_PROP_PWR_GRID_50HZ = 0b0000000000000000, + SI476X_PROP_PWR_GRID_60HZ = 0b0000000100000000, +}; + +enum si476x_prop_fm_rds_config_bits { + SI476X_PROP_RDSEN_MASK = 0x1, + SI476X_PROP_RDSEN = 0x1, +}; + + +struct regmap *devm_regmap_init_si476x(struct si476x_core *); + +#endif /* SI476X_CORE_H */ -- cgit v1.2.3 From aec330a8cbd373d78c327201ec28fd5f252f3846 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:23 -0300 Subject: [media] v4l2: Add standard controls for FM receivers This commit introduces new class of standard controls V4L2_CTRL_CLASS_FM_RX. This class is intended to all controls pertaining to FM receiver chips. Also, two controls belonging to said class are added as a part of this commit: V4L2_CID_TUNE_DEEMPHASIS and V4L2_CID_RDS_RECEPTION. This patch is based on the code found in the patch by Manjunatha Halli [1] [1] http://lists-archives.com/linux-kernel/27641307-new-control-class-and-features-for-fm-rx.html Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 14 +++++++++++--- include/uapi/linux/v4l2-controls.h | 13 +++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f662df3bfe2d..ec89fd16361c 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -297,8 +297,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Text", NULL }; - static const char * const tune_preemphasis[] = { - "No Preemphasis", + static const char * const tune_emphasis[] = { + "None", "50 Microseconds", "75 Microseconds", NULL, @@ -508,7 +508,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id) case V4L2_CID_SCENE_MODE: return scene_mode; case V4L2_CID_TUNE_PREEMPHASIS: - return tune_preemphasis; + return tune_emphasis; + case V4L2_CID_TUNE_DEEMPHASIS: + return tune_emphasis; case V4L2_CID_FLASH_LED_MODE: return flash_led_mode; case V4L2_CID_FLASH_STROBE_SOURCE: @@ -800,6 +802,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present"; case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range"; + case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls"; + case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis"; + case V4L2_CID_RDS_RECEPTION: return "RDS Reception"; default: return NULL; } @@ -848,6 +853,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: case V4L2_CID_WIDE_DYNAMIC_RANGE: case V4L2_CID_IMAGE_STABILIZATION: + case V4L2_CID_RDS_RECEPTION: *type = V4L2_CTRL_TYPE_BOOLEAN; *min = 0; *max = *step = 1; @@ -906,6 +912,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_TX_RGB_RANGE: case V4L2_CID_DV_RX_RGB_RANGE: case V4L2_CID_TEST_PATTERN: + case V4L2_CID_TUNE_DEEMPHASIS: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: @@ -928,6 +935,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_IMAGE_SOURCE_CLASS: case V4L2_CID_IMAGE_PROC_CLASS: case V4L2_CID_DV_CLASS: + case V4L2_CID_FM_RX_CLASS: *type = V4L2_CTRL_TYPE_CTRL_CLASS; /* You can neither read not write these */ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 844dc0205037..7d2604877a73 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -59,6 +59,7 @@ #define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009e0000 /* Image source controls */ #define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000 /* Image processing controls */ #define V4L2_CTRL_CLASS_DV 0x00a00000 /* Digital Video controls */ +#define V4L2_CTRL_CLASS_FM_RX 0x00a10000 /* Digital Video controls */ /* User-class control IDs */ @@ -835,4 +836,16 @@ enum v4l2_dv_rgb_range { #define V4L2_CID_DV_RX_POWER_PRESENT (V4L2_CID_DV_CLASS_BASE + 100) #define V4L2_CID_DV_RX_RGB_RANGE (V4L2_CID_DV_CLASS_BASE + 101) +#define V4L2_CID_FM_RX_CLASS_BASE (V4L2_CTRL_CLASS_FM_RX | 0x900) +#define V4L2_CID_FM_RX_CLASS (V4L2_CTRL_CLASS_FM_RX | 1) + +#define V4L2_CID_TUNE_DEEMPHASIS (V4L2_CID_FM_RX_CLASS_BASE + 1) +enum v4l2_deemphasis { + V4L2_DEEMPHASIS_DISABLED = V4L2_PREEMPHASIS_DISABLED, + V4L2_DEEMPHASIS_50_uS = V4L2_PREEMPHASIS_50_uS, + V4L2_DEEMPHASIS_75_uS = V4L2_PREEMPHASIS_75_uS, +}; + +#define V4L2_CID_RDS_RECEPTION (V4L2_CID_FM_RX_CLASS_BASE + 2) + #endif -- cgit v1.2.3 From 33a80fc2eb43afbc25f04cc1d5ed899da213c21f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:25 -0300 Subject: [media] v4l2: Add private controls base for SI476X Add a base to be used for allocation of all the SI476X specific controls in the corresponding driver. Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-controls.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7d2604877a73..910d7cd3d9f4 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -156,6 +156,10 @@ enum v4l2_colorfx { * We reserve 8 controls for this driver. */ #define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1010) +/* The base for the si476x driver controls. See include/media/si476x.h for the list + * of controls. Total of 16 controls is reserved for that driver */ +#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1010) + /* MPEG-class control IDs */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -- cgit v1.2.3 From 30bac9110455402fa8888740c6819dd3daa2666f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:26 -0300 Subject: [media] v4l2: Add a V4L2 driver for SI476X MFD This commit adds a driver that exposes all the radio related functionality of the Si476x series of chips via the V4L2 subsystem. Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/si476x.txt | 187 ++++ drivers/media/radio/Kconfig | 17 + drivers/media/radio/Makefile | 1 + drivers/media/radio/radio-si476x.c | 1599 ++++++++++++++++++++++++++++++++++ include/media/si476x.h | 426 +++++++++ 5 files changed, 2230 insertions(+) create mode 100644 Documentation/video4linux/si476x.txt create mode 100644 drivers/media/radio/radio-si476x.c create mode 100644 include/media/si476x.h (limited to 'include') diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt new file mode 100644 index 000000000000..d1a08db2cbd9 --- /dev/null +++ b/Documentation/video4linux/si476x.txt @@ -0,0 +1,187 @@ +SI476x Driver Readme +------------------------------------------------ + Copyright (C) 2013 Andrey Smirnov + +TODO for the driver +------------------------------ + +- According to the SiLabs' datasheet it is possible to update the + firmware of the radio chip in the run-time, thus bringing it to the + most recent version. Unfortunately I couldn't find any mentioning of + the said firmware update for the old chips that I tested the driver + against, so for chips like that the driver only exposes the old + functionality. + + +Parameters exposed over debugfs +------------------------------- +SI476x allow user to get multiple characteristics that can be very +useful for EoL testing/RF performance estimation, parameters that have +very little to do with V4L2 subsystem. Such parameters are exposed via +debugfs and can be accessed via regular file I/O operations. + +The drivers exposes following files: + +* /sys/kernel/debug//acf + This file contains ACF(Automatically Controlled Features) status + information. The contents of the file is binary data of the + following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | blend_int | Flag, set when stereo separation has + | | crossed below the blend threshold + -------------------------------------------------------------------- + 0x01 | hblend_int | Flag, set when HiBlend cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x02 | hicut_int | Flag, set when HiCut cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x03 | chbw_int | Flag, set when channel filter + | | bandwidth is less than threshold + -------------------------------------------------------------------- + 0x04 | softmute_int | Flag indicating that softmute + | | attenuation has increased above + | | softmute threshold + -------------------------------------------------------------------- + 0x05 | smute | 0 - Audio is not soft muted + | | 1 - Audio is soft muted + -------------------------------------------------------------------- + 0x06 | smattn | Soft mute attenuation level in dB + -------------------------------------------------------------------- + 0x07 | chbw | Channel filter bandwidth in kHz + -------------------------------------------------------------------- + 0x08 | hicut | HiCut cutoff frequency in units of + | | 100Hz + -------------------------------------------------------------------- + 0x09 | hiblend | HiBlend cutoff frequency in units + | | of 100 Hz + -------------------------------------------------------------------- + 0x10 | pilot | 0 - Stereo pilot is not present + | | 1 - Stereo pilot is present + -------------------------------------------------------------------- + 0x11 | stblend | Stereo blend in % + -------------------------------------------------------------------- + + +* /sys/kernel/debug//rds_blckcnt + This file contains statistics about RDS receptions. It's binary data + has the following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | expected | Number of expected RDS blocks + -------------------------------------------------------------------- + 0x02 | received | Number of received RDS blocks + -------------------------------------------------------------------- + 0x04 | uncorrectable | Number of uncorrectable RDS blocks + -------------------------------------------------------------------- + +* /sys/kernel/debug//agc + This file contains information about parameters pertaining to + AGC(Automatic Gain Control) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | mxhi | 0 - FM Mixer PD high threshold is + | | not tripped + | | 1 - FM Mixer PD high threshold is + | | tripped + -------------------------------------------------------------------- + 0x01 | mxlo | ditto for FM Mixer PD low + -------------------------------------------------------------------- + 0x02 | lnahi | ditto for FM LNA PD high + -------------------------------------------------------------------- + 0x03 | lnalo | ditto for FM LNA PD low + -------------------------------------------------------------------- + 0x04 | fmagc1 | FMAGC1 attenuator resistance + | | (see datasheet for more detail) + -------------------------------------------------------------------- + 0x05 | fmagc2 | ditto for FMAGC2 + -------------------------------------------------------------------- + 0x06 | pgagain | PGA gain in dB + -------------------------------------------------------------------- + 0x07 | fmwblang | FM/WB LNA Gain in dB + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | multhint | 0 - multipath value has not crossed + | | the Multipath high threshold + | | 1 - multipath value has crossed + | | the Multipath high threshold + -------------------------------------------------------------------- + 0x01 | multlint | ditto for Multipath low threshold + -------------------------------------------------------------------- + 0x02 | snrhint | 0 - received signal's SNR has not + | | crossed high threshold + | | 1 - received signal's SNR has + | | crossed high threshold + -------------------------------------------------------------------- + 0x03 | snrlint | ditto for low threshold + -------------------------------------------------------------------- + 0x04 | rssihint | ditto for RSSI high threshold + -------------------------------------------------------------------- + 0x05 | rssilint | ditto for RSSI low threshold + -------------------------------------------------------------------- + 0x06 | bltf | Flag indicating if seek command + | | reached/wrapped seek band limit + -------------------------------------------------------------------- + 0x07 | snr_ready | Indicates that SNR metrics is ready + -------------------------------------------------------------------- + 0x08 | rssiready | ditto for RSSI metrics + -------------------------------------------------------------------- + 0x09 | injside | 0 - Low-side injection is being used + | | 1 - High-side injection is used + -------------------------------------------------------------------- + 0x10 | afcrl | Flag indicating if AFC rails + -------------------------------------------------------------------- + 0x11 | valid | Flag indicating if channel is valid + -------------------------------------------------------------------- + 0x12 | readfreq | Current tuned frequency + -------------------------------------------------------------------- + 0x14 | freqoff | Singed frequency offset in units of + | | 2ppm + -------------------------------------------------------------------- + 0x15 | rssi | Signed value of RSSI in dBuV + -------------------------------------------------------------------- + 0x16 | snr | Signed RF SNR in dB + -------------------------------------------------------------------- + 0x17 | issi | Signed Image Strength Signal + | | indicator + -------------------------------------------------------------------- + 0x18 | lassi | Signed Low side adjacent Channel + | | Strength indicator + -------------------------------------------------------------------- + 0x19 | hassi | ditto fpr High side + -------------------------------------------------------------------- + 0x20 | mult | Multipath indicator + -------------------------------------------------------------------- + 0x21 | dev | Frequency deviation + -------------------------------------------------------------------- + 0x24 | assi | Adjascent channel SSI + -------------------------------------------------------------------- + 0x25 | usn | Ultrasonic noise indicator + -------------------------------------------------------------------- + 0x26 | pilotdev | Pilot deviation in units of 100 Hz + -------------------------------------------------------------------- + 0x27 | rdsdev | ditto for RDS + -------------------------------------------------------------------- + 0x28 | assidev | ditto for ASSI + -------------------------------------------------------------------- + 0x29 | strongdev | Frequency deviation + -------------------------------------------------------------------- + 0x30 | rdspi | RDS PI code + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq_primary + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) for primary tuner only. Layout is as + the one above. diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 24e64a09884c..28ded247abc0 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -18,6 +18,23 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" +config RADIO_SI476X + tristate "Silicon Laboratories Si476x I2C FM Radio" + depends on I2C && VIDEO_V4L2 + select MFD_CORE + select MFD_SI476X_CORE + select SND_SOC_SI476X + ---help--- + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-si476x. + config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 303eaebdb85a..0dcdb320cfc7 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o +obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c new file mode 100644 index 000000000000..0895a0c23787 --- /dev/null +++ b/drivers/media/radio/radio-si476x.c @@ -0,0 +1,1599 @@ +/* + * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define FM_FREQ_RANGE_LOW 64000000 +#define FM_FREQ_RANGE_HIGH 108000000 + +#define AM_FREQ_RANGE_LOW 520000 +#define AM_FREQ_RANGE_HIGH 30000000 + +#define PWRLINEFLTR (1 << 8) + +#define FREQ_MUL (10000000 / 625) + +#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) + +#define DRIVER_NAME "si476x-radio" +#define DRIVER_CARD "SI476x AM/FM Receiver" + +enum si476x_freq_bands { + SI476X_BAND_FM, + SI476X_BAND_AM, +}; + +static const struct v4l2_frequency_band si476x_bands[] = { + [SI476X_BAND_FM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_FM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 64 * FREQ_MUL, + .rangehigh = 108 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_FM, + }, + [SI476X_BAND_AM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_AM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 0.52 * FREQ_MUL, + .rangehigh = 30 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_AM, + }, +}; + +static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band) +{ + return freq >= si476x_bands[band].rangelow && + freq <= si476x_bands[band].rangehigh; +} + +static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high, + int band) +{ + return low >= si476x_bands[band].rangelow && + high <= si476x_bands[band].rangehigh; +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl); +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl); + +enum phase_diversity_modes_idx { + SI476X_IDX_PHDIV_DISABLED, + SI476X_IDX_PHDIV_PRIMARY_COMBINING, + SI476X_IDX_PHDIV_PRIMARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_COMBINING, +}; + +static const char * const phase_diversity_modes[] = { + [SI476X_IDX_PHDIV_DISABLED] = "Disabled", + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary", + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary", +}; + +static inline enum phase_diversity_modes_idx +si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode) +{ + switch (mode) { + default: /* FALLTHROUGH */ + case SI476X_PHDIV_DISABLED: + return SI476X_IDX_PHDIV_DISABLED; + case SI476X_PHDIV_PRIMARY_COMBINING: + return SI476X_IDX_PHDIV_PRIMARY_COMBINING; + case SI476X_PHDIV_PRIMARY_ANTENNA: + return SI476X_IDX_PHDIV_PRIMARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_ANTENNA: + return SI476X_IDX_PHDIV_SECONDARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_COMBINING: + return SI476X_IDX_PHDIV_SECONDARY_COMBINING; + } +} + +static inline enum si476x_phase_diversity_mode +si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx) +{ + static const int idx_to_value[] = { + [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED, + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING, + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING, + }; + + return idx_to_value[idx]; +} + +static const struct v4l2_ctrl_ops si476x_ctrl_ops = { + .g_volatile_ctrl = si476x_radio_g_volatile_ctrl, + .s_ctrl = si476x_radio_s_ctrl, +}; + + +enum si476x_ctrl_idx { + SI476X_IDX_RSSI_THRESHOLD, + SI476X_IDX_SNR_THRESHOLD, + SI476X_IDX_MAX_TUNE_ERROR, + SI476X_IDX_HARMONICS_COUNT, + SI476X_IDX_DIVERSITY_MODE, + SI476X_IDX_INTERCHIP_LINK, +}; +static struct v4l2_ctrl_config si476x_ctrls[] = { + + /** + * SI476X during its station seeking(or tuning) process uses several + * parameters to detrmine if "the station" is valid: + * + * - Signal's SNR(in dBuV) must be lower than + * #V4L2_CID_SI476X_SNR_THRESHOLD + * - Signal's RSSI(in dBuV) must be greater than + * #V4L2_CID_SI476X_RSSI_THRESHOLD + * - Signal's frequency deviation(in units of 2ppm) must not be + * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR + */ + [SI476X_IDX_RSSI_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_RSSI_THRESHOLD, + .name = "Valid RSSI Threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_SNR_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_SNR_THRESHOLD, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Valid SNR Threshold", + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_MAX_TUNE_ERROR] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_MAX_TUNE_ERROR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Max Tune Errors", + .min = 0, + .max = 126 * 2, + .step = 2, + }, + + /** + * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics + * built-in power-line noise supression filter is to reject + * during AM-mode operation. + */ + [SI476X_IDX_HARMONICS_COUNT] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_HARMONICS_COUNT, + .type = V4L2_CTRL_TYPE_INTEGER, + + .name = "Count of Harmonics to Reject", + .min = 0, + .max = 20, + .step = 1, + }, + + /** + * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which + * two tuners working in diversity mode are to work in. + * + * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled + * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is + * on, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is + * off, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is + * off, secondary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is + * on, secondary tuner's antenna is the main one. + */ + [SI476X_IDX_DIVERSITY_MODE] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_DIVERSITY_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Phase Diversity Mode", + .qmenu = phase_diversity_modes, + .min = 0, + .max = ARRAY_SIZE(phase_diversity_modes) - 1, + }, + + /** + * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in + * diversity mode indicator. Allows user to determine if two + * chips working in diversity mode have established a link + * between each other and if the system as a whole uses + * signals from both antennas to receive FM radio. + */ + [SI476X_IDX_INTERCHIP_LINK] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_INTERCHIP_LINK, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, + .name = "Inter-Chip Link", + .min = 0, + .max = 1, + .step = 1, + }, +}; + +struct si476x_radio; + +/** + * struct si476x_radio_ops - vtable of tuner functions + * + * This table holds pointers to functions implementing particular + * operations depending on the mode in which the tuner chip was + * configured to start in. If the function is not supported + * corresponding element is set to #NULL. + * + * @tune_freq: Tune chip to a specific frequency + * @seek_start: Star station seeking + * @rsq_status: Get Recieved Signal Quality(RSQ) status + * @rds_blckcnt: Get recived RDS blocks count + * @phase_diversity: Change phase diversity mode of the tuner + * @phase_div_status: Get phase diversity mode status + * @acf_status: Get the status of Automatically Controlled + * Features(ACF) + * @agc_status: Get Automatic Gain Control(AGC) status + */ +struct si476x_radio_ops { + int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *); + int (*seek_start)(struct si476x_core *, bool, bool); + int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); + int (*rds_blckcnt)(struct si476x_core *, bool, + struct si476x_rds_blockcount_report *); + + int (*phase_diversity)(struct si476x_core *, + enum si476x_phase_diversity_mode); + int (*phase_div_status)(struct si476x_core *); + int (*acf_status)(struct si476x_core *, + struct si476x_acf_status_report *); + int (*agc_status)(struct si476x_core *, + struct si476x_agc_status_report *); +}; + +/** + * struct si476x_radio - radio device + * + * @core: Pointer to underlying core device + * @videodev: Pointer to video device created by V4L2 subsystem + * @ops: Vtable of functions. See struct si476x_radio_ops for details + * @kref: Reference counter + * @core_lock: An r/w semaphore to brebvent the deletion of underlying + * core structure is the radio device is being used + */ +struct si476x_radio { + struct v4l2_device v4l2dev; + struct video_device videodev; + struct v4l2_ctrl_handler ctrl_handler; + + struct si476x_core *core; + /* This field should not be accesses unless core lock is held */ + const struct si476x_radio_ops *ops; + + struct dentry *debugfs; + u32 audmode; +}; + +static inline struct si476x_radio * +v4l2_dev_to_radio(struct v4l2_device *d) +{ + return container_of(d, struct si476x_radio, v4l2dev); +} + +static inline struct si476x_radio * +v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) +{ + return container_of(d, struct si476x_radio, ctrl_handler); +} + +/* + * si476x_vidioc_querycap - query device capabilities + */ +static int si476x_radio_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + struct si476x_radio *radio = video_drvdata(file); + + strlcpy(capability->driver, radio->v4l2dev.name, + sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + snprintf(capability->bus_info, sizeof(capability->bus_info), + "platform:%s", radio->v4l2dev.name); + + capability->device_caps = V4L2_CAP_TUNER + | V4L2_CAP_RADIO + | V4L2_CAP_HW_FREQ_SEEK; + + si476x_core_lock(radio->core); + if (!si476x_core_is_a_secondary_tuner(radio->core)) + capability->device_caps |= V4L2_CAP_RDS_CAPTURE + | V4L2_CAP_READWRITE; + si476x_core_unlock(radio->core); + + capability->capabilities = capability->device_caps + | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int si476x_radio_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (band->tuner != 0) + return -EINVAL; + + switch (radio->core->chip_id) { + /* AM/FM tuners -- all bands are supported */ + case SI476X_CHIP_SI4761: + case SI476X_CHIP_SI4764: + if (band->index < ARRAY_SIZE(si476x_bands)) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + /* FM companion tuner chips -- only FM bands are + * supported */ + case SI476X_CHIP_SI4768: + if (band->index == SI476X_BAND_FM) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + default: + err = -EINVAL; + } + + return err; +} + +static int si476x_radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + int err; + struct si476x_rsq_status_report report; + struct si476x_radio *radio = video_drvdata(file); + + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + if (tuner->index != 0) + return -EINVAL; + + tuner->type = V4L2_TUNER_RADIO; + tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies + * in multiples of + * 62.5 Hz */ + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_HWSEEK_BOUNDED + | V4L2_TUNER_CAP_HWSEEK_WRAP + | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; + + si476x_core_lock(radio->core); + + if (si476x_core_is_a_secondary_tuner(radio->core)) { + strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); + tuner->rxsubchans = 0; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } else if (si476x_core_has_am(radio->core)) { + if (si476x_core_is_a_primary_tuner(radio->core)) + strlcpy(tuner->name, "AM/FM (primary)", + sizeof(tuner->name)); + else + strlcpy(tuner->name, "AM/FM", sizeof(tuner->name)); + + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO + | V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + + tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; + } else { + strlcpy(tuner->name, "FM", sizeof(tuner->name)); + tuner->rxsubchans = V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } + + tuner->audmode = radio->audmode; + + tuner->afc = 1; + tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; + + err = radio->ops->rsq_status(radio->core, + &args, &report); + if (err < 0) { + tuner->signal = 0; + } else { + /* + * tuner->signal value range: 0x0000 .. 0xFFFF, + * report.rssi: -128 .. 127 + */ + tuner->signal = (report.rssi + 128) * 257; + } + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct si476x_radio *radio = video_drvdata(file); + + if (tuner->index != 0) + return -EINVAL; + + if (tuner->audmode == V4L2_TUNER_MODE_MONO || + tuner->audmode == V4L2_TUNER_MODE_STEREO) + radio->audmode = tuner->audmode; + else + radio->audmode = V4L2_TUNER_MODE_STEREO; + + return 0; +} + +static int si476x_radio_init_vtable(struct si476x_radio *radio, + enum si476x_func func) +{ + static const struct si476x_radio_ops fm_ops = { + .tune_freq = si476x_core_cmd_fm_tune_freq, + .seek_start = si476x_core_cmd_fm_seek_start, + .rsq_status = si476x_core_cmd_fm_rsq_status, + .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, + .phase_diversity = si476x_core_cmd_fm_phase_diversity, + .phase_div_status = si476x_core_cmd_fm_phase_div_status, + .acf_status = si476x_core_cmd_fm_acf_status, + .agc_status = si476x_core_cmd_agc_status, + }; + + static const struct si476x_radio_ops am_ops = { + .tune_freq = si476x_core_cmd_am_tune_freq, + .seek_start = si476x_core_cmd_am_seek_start, + .rsq_status = si476x_core_cmd_am_rsq_status, + .rds_blckcnt = NULL, + .phase_diversity = NULL, + .phase_div_status = NULL, + .acf_status = si476x_core_cmd_am_acf_status, + .agc_status = NULL, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + radio->ops = &fm_ops; + return 0; + + case SI476X_FUNC_AM_RECEIVER: + radio->ops = &am_ops; + return 0; + default: + WARN(1, "Unexpected tuner function value\n"); + return -EINVAL; + } +} + +static int si476x_radio_pretune(struct si476x_radio *radio, + enum si476x_func func) +{ + int retval; + + struct si476x_tune_freq_args args = { + .zifsr = false, + .hd = false, + .injside = SI476X_INJSIDE_AUTO, + .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, + .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, + .antcap = 0, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 92 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + case SI476X_FUNC_AM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 0.6 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + default: + WARN(1, "Unexpected tuner function value\n"); + retval = -EINVAL; + } + + return retval; +} +static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + + /* regcache_mark_dirty(radio->core->regmap); */ + 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; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + SI476X_PROP_AUDIO_PWR_LINE_FILTER); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_INT_CTL_ENABLE, + SI476X_PROP_INT_CTL_ENABLE); + if (err < 0) + return err; + + /* + * Is there any point in restoring SNR and the like + * when switching between AM/FM? + */ + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + SI476X_PROP_VALID_MAX_TUNE_ERROR); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + SI476X_PROP_VALID_RSSI_THRESHOLD); + if (err < 0) + return err; + + if (func == SI476X_FUNC_FM_RECEIVER) { + if (si476x_core_has_diversity(radio->core)) { + err = si476x_core_cmd_fm_phase_diversity(radio->core, + radio->core->diversity_mode); + if (err < 0) + return err; + } + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_PROP_FM_RDS_CONFIG); + if (err < 0) + return err; + } + + return si476x_radio_init_vtable(radio, func); + +} + +static int si476x_radio_change_func(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + bool soft; + /* + * Since power/up down is a very time consuming operation, + * try to avoid doing it if the requested mode matches the one + * the tuner is in + */ + if (func == radio->core->power_up_parameters.func) + return 0; + + soft = true; + err = si476x_core_stop(radio->core, soft); + if (err < 0) { + /* + * OK, if the chip does not want to play nice let's + * try to reset it in more brutal way + */ + soft = false; + err = si476x_core_stop(radio->core, soft); + if (err < 0) + return err; + } + /* + Set the desired radio tuner function + */ + radio->core->power_up_parameters.func = func; + + err = si476x_core_start(radio->core, soft); + if (err < 0) + return err; + + /* + * No need to do the rest of manipulations for the bootlader + * mode + */ + if (func != SI476X_FUNC_FM_RECEIVER && + func != SI476X_FUNC_AM_RECEIVER) + return err; + + return si476x_radio_do_post_powerup_init(radio, func); +} + +static int si476x_radio_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (radio->ops->rsq_status) { + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = true, + .cancel = false, + .stcack = false, + }; + + err = radio->ops->rsq_status(radio->core, &args, &report); + if (!err) + f->frequency = si476x_to_v4l2(radio->core, + report.readfreq); + } else { + err = -EINVAL; + } + + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + int err; + struct si476x_tune_freq_args args; + struct si476x_radio *radio = video_drvdata(file); + + const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + + si476x_bands[SI476X_BAND_FM].rangelow) / 2; + const int band = (f->frequency > midrange) ? + SI476X_BAND_FM : SI476X_BAND_AM; + const enum si476x_func func = (band == SI476X_BAND_AM) ? + SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + f->frequency = clamp(f->frequency, + si476x_bands[band].rangelow, + si476x_bands[band].rangehigh); + + if (si476x_radio_freq_is_inside_of_the_band(f->frequency, + SI476X_BAND_AM) && + (!si476x_core_has_am(radio->core) || + si476x_core_is_a_secondary_tuner(radio->core))) { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + args.zifsr = false; + args.hd = false; + args.injside = SI476X_INJSIDE_AUTO; + args.freq = v4l2_to_si476x(radio->core, + f->frequency); + args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; + args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; + args.antcap = 0; + + err = radio->ops->tune_freq(radio->core, &args); + +unlock: + si476x_core_unlock(radio->core); + return err; +} + +static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, + const struct v4l2_hw_freq_seek *seek) +{ + int err; + enum si476x_func func; + u32 rangelow, rangehigh; + struct si476x_radio *radio = video_drvdata(file); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (seek->tuner != 0 || + seek->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (!seek->rangelow) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + &rangelow); + if (!err) + rangelow = si476x_to_v4l2(radio->core, rangelow); + else + goto unlock; + } + if (!seek->rangehigh) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + &rangehigh); + if (!err) + rangehigh = si476x_to_v4l2(radio->core, rangehigh); + else + goto unlock; + } + + if (rangelow > rangehigh) { + err = -EINVAL; + goto unlock; + } + + if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_FM)) { + func = SI476X_FUNC_FM_RECEIVER; + + } else if (si476x_core_has_am(radio->core) && + si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_AM)) { + func = SI476X_FUNC_AM_RECEIVER; + } else { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + if (seek->rangehigh) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + v4l2_to_si476x(radio->core, + seek->rangehigh)); + if (err) + goto unlock; + } + if (seek->rangelow) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + v4l2_to_si476x(radio->core, + seek->rangelow)); + if (err) + goto unlock; + } + if (seek->spacing) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_FREQUENCY_SPACING, + v4l2_to_si476x(radio->core, + seek->spacing)); + if (err) + goto unlock; + } + + err = radio->ops->seek_start(radio->core, + seek->seek_upward, + seek->wrap_around); +unlock: + si476x_core_unlock(radio->core); + + + + return err; +} + +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_INTERCHIP_LINK: + if (si476x_core_has_diversity(radio->core)) { + if (radio->ops->phase_diversity) { + retval = radio->ops->phase_div_status(radio->core); + if (retval < 0) + break; + + ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); + retval = 0; + break; + } else { + retval = -ENOTTY; + break; + } + } + retval = -EINVAL; + break; + default: + retval = -EINVAL; + break; + } + si476x_core_unlock(radio->core); + return retval; + +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + enum si476x_phase_diversity_mode mode; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_HARMONICS_COUNT: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_HARMONICS_MASK, + ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (ctrl->val) { + case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_ENABLE_MASK, + 0); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_50HZ); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_60HZ); + break; + default: + retval = -EINVAL; + break; + } + break; + case V4L2_CID_SI476X_RSSI_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_RSSI_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_SNR_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_MAX_TUNE_ERROR: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + ctrl->val); + break; + case V4L2_CID_RDS_RECEPTION: + /* + * It looks like RDS related properties are + * inaccesable when tuner is in AM mode, so cache the + * changes + */ + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, true); + + if (ctrl->val) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, + radio->core->rds_fifo_depth); + if (retval < 0) + break; + + if (radio->core->client->irq) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_RDSRECV); + if (retval < 0) + break; + } + + /* Drain RDS FIFO before enabling RDS processing */ + retval = si476x_core_cmd_fm_rds_status(radio->core, + false, + true, + true, + NULL); + if (retval < 0) + break; + + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + SI476X_PROP_RDSEN); + } else { + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + !SI476X_PROP_RDSEN); + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, false); + break; + case V4L2_CID_TUNE_DEEMPHASIS: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + ctrl->val); + break; + + case V4L2_CID_SI476X_DIVERSITY_MODE: + mode = si476x_phase_diversity_idx_to_mode(ctrl->val); + + if (mode == radio->core->diversity_mode) { + retval = 0; + break; + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) { + /* + * Diversity cannot be configured while tuner + * is in AM mode so save the changes and carry on. + */ + radio->core->diversity_mode = mode; + retval = 0; + } else { + retval = radio->ops->phase_diversity(radio->core, mode); + if (!retval) + radio->core->diversity_mode = mode; + } + break; + + default: + retval = -EINVAL; + break; + } + + si476x_core_unlock(radio->core); + + return retval; +} + +static int si476x_radio_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + if (chip->match.type == V4L2_CHIP_MATCH_HOST && + v4l2_chip_match_host(&chip->match)) + return 0; + return -EINVAL; +} + + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int si476x_radio_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + int err; + unsigned int value; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + reg->size = 2; + err = regmap_read(radio->core->regmap, + (unsigned int)reg->reg, &value); + reg->val = value; + si476x_core_unlock(radio->core); + + return err; +} +static int si476x_radio_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + + int err; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + err = regmap_write(radio->core->regmap, + (unsigned int)reg->reg, + (unsigned int)reg->val); + si476x_core_unlock(radio->core); + + return err; +} +#endif + +static int si476x_radio_fops_open(struct file *file) +{ + struct si476x_radio *radio = video_drvdata(file); + int err; + + err = v4l2_fh_open(file); + if (err) + return err; + + if (v4l2_fh_is_singular_file(file)) { + si476x_core_lock(radio->core); + err = si476x_core_set_power_state(radio->core, + SI476X_POWER_UP_FULL); + if (err < 0) + goto done; + + err = si476x_radio_do_post_powerup_init(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + err = si476x_radio_pretune(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + si476x_core_unlock(radio->core); + /*Must be done after si476x_core_unlock to prevent a deadlock*/ + v4l2_ctrl_handler_setup(&radio->ctrl_handler); + } + + return err; + +power_down: + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); +done: + si476x_core_unlock(radio->core); + v4l2_fh_release(file); + + return err; +} + +static int si476x_radio_fops_release(struct file *file) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (v4l2_fh_is_singular_file(file) && + atomic_read(&radio->core->is_alive)) + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); + + err = v4l2_fh_release(file); + + return err; +} + +static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t rval; + size_t fifo_len; + unsigned int copied; + + struct si476x_radio *radio = video_drvdata(file); + + /* block if no new data available */ + if (kfifo_is_empty(&radio->core->rds_fifo)) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + rval = wait_event_interruptible(radio->core->rds_read_queue, + (!kfifo_is_empty(&radio->core->rds_fifo) || + !atomic_read(&radio->core->is_alive))); + if (rval < 0) + return -EINTR; + + if (!atomic_read(&radio->core->is_alive)) + return -ENODEV; + } + + fifo_len = kfifo_len(&radio->core->rds_fifo); + + if (kfifo_to_user(&radio->core->rds_fifo, buf, + min(fifo_len, count), + &copied) != 0) { + dev_warn(&radio->videodev.dev, + "Error during FIFO to userspace copy\n"); + rval = -EIO; + } else { + rval = (ssize_t)copied; + } + + return rval; +} + +static unsigned int si476x_radio_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si476x_radio *radio = video_drvdata(file); + unsigned long req_events = poll_requested_events(pts); + unsigned int err = v4l2_ctrl_poll(file, pts); + + if (req_events & (POLLIN | POLLRDNORM)) { + if (atomic_read(&radio->core->is_alive)) + poll_wait(file, &radio->core->rds_read_queue, pts); + + if (!atomic_read(&radio->core->is_alive)) + err = POLLHUP; + + if (!kfifo_is_empty(&radio->core->rds_fifo)) + err = POLLIN | POLLRDNORM; + } + + return err; +} + +static const struct v4l2_file_operations si476x_fops = { + .owner = THIS_MODULE, + .read = si476x_radio_fops_read, + .poll = si476x_radio_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = si476x_radio_fops_open, + .release = si476x_radio_fops_release, +}; + + +static const struct v4l2_ioctl_ops si4761_ioctl_ops = { + .vidioc_querycap = si476x_radio_querycap, + .vidioc_g_tuner = si476x_radio_g_tuner, + .vidioc_s_tuner = si476x_radio_s_tuner, + + .vidioc_g_frequency = si476x_radio_g_frequency, + .vidioc_s_frequency = si476x_radio_s_frequency, + .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, + .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_g_chip_ident = si476x_radio_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = si476x_radio_g_register, + .vidioc_s_register = si476x_radio_s_register, +#endif +}; + + +static const struct video_device si476x_viddev_template = { + .fops = &si476x_fops, + .name = DRIVER_NAME, + .release = video_device_release_empty, +}; + + + +static ssize_t si476x_radio_read_acf_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_acf_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->acf_status) + err = radio->ops->acf_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_acf_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_acf_blob, +}; + +static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rds_blockcount_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rds_blckcnt(radio->core, true, + &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rds_blckcnt_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rds_blckcnt_blob, +}; + +static ssize_t si476x_radio_read_agc_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_agc_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->agc_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_agc_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_agc_blob, +}; + +static ssize_t si476x_radio_read_rsq_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_blob, +}; + +static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = true, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_primary_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_primary_blob, +}; + + +static int si476x_radio_init_debugfs(struct si476x_radio *radio) +{ + struct dentry *dentry; + int ret; + + dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto exit; + } + radio->debugfs = dentry; + + dentry = debugfs_create_file("acf", S_IRUGO, + radio->debugfs, radio, &radio_acf_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rds_blckcnt", S_IRUGO, + radio->debugfs, radio, + &radio_rds_blckcnt_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("agc", S_IRUGO, + radio->debugfs, radio, &radio_agc_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq", S_IRUGO, + radio->debugfs, radio, &radio_rsq_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq_primary", S_IRUGO, + radio->debugfs, radio, + &radio_rsq_primary_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + return 0; +cleanup: + debugfs_remove_recursive(radio->debugfs); +exit: + return ret; +} + + +static int si476x_radio_add_new_custom(struct si476x_radio *radio, + enum si476x_ctrl_idx idx) +{ + int rval; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, + &si476x_ctrls[idx], + NULL); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) + dev_err(radio->v4l2dev.dev, + "Could not initialize '%s' control %d\n", + si476x_ctrls[idx].name, rval); + + return rval; +} + +static int si476x_radio_probe(struct platform_device *pdev) +{ + int rval; + struct si476x_radio *radio; + struct v4l2_ctrl *ctrl; + + static atomic_t instance = ATOMIC_INIT(0); + + radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); + if (!radio) + return -ENOMEM; + + radio->core = i2c_mfd_cell_to_core(&pdev->dev); + + v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); + + rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); + if (rval) { + dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); + return rval; + } + + memcpy(&radio->videodev, &si476x_viddev_template, + sizeof(struct video_device)); + + radio->videodev.v4l2_dev = &radio->v4l2dev; + radio->videodev.ioctl_ops = &si4761_ioctl_ops; + + video_set_drvdata(&radio->videodev, radio); + platform_set_drvdata(pdev, radio); + + set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); + + radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; + v4l2_ctrl_handler_init(&radio->ctrl_handler, + 1 + ARRAY_SIZE(si476x_ctrls)); + + if (si476x_core_has_am(radio->core)) { + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", + rval); + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, + SI476X_IDX_HARMONICS_COUNT); + if (rval < 0) + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); + if (rval < 0) + goto exit; + + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_TUNE_DEEMPHASIS, + V4L2_DEEMPHASIS_75_uS, 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", + rval); + goto exit; + } + + ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, + V4L2_CID_RDS_RECEPTION, + 0, 1, 1, 1); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", + rval); + goto exit; + } + + if (si476x_core_has_diversity(radio->core)) { + si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = + si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); + si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); + if (rval < 0) + goto exit; + + si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); + if (rval < 0) + goto exit; + } + + /* register video device */ + rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); + if (rval < 0) { + dev_err(&pdev->dev, "Could not register video device\n"); + goto exit; + } + + rval = si476x_radio_init_debugfs(radio); + if (rval < 0) { + dev_err(&pdev->dev, "Could not creat debugfs interface\n"); + goto exit; + } + + return 0; +exit: + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + return rval; +} + +static int si476x_radio_remove(struct platform_device *pdev) +{ + struct si476x_radio *radio = platform_get_drvdata(pdev); + + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + video_unregister_device(&radio->videodev); + v4l2_device_unregister(&radio->v4l2dev); + debugfs_remove_recursive(radio->debugfs); + + return 0; +} + +MODULE_ALIAS("platform:si476x-radio"); + +static struct platform_driver si476x_radio_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = si476x_radio_probe, + .remove = si476x_radio_remove, +}; +module_platform_driver(si476x_radio_driver); + +MODULE_AUTHOR("Andrey Smirnov "); +MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); +MODULE_LICENSE("GPL"); diff --git a/include/media/si476x.h b/include/media/si476x.h new file mode 100644 index 000000000000..beb6433d6958 --- /dev/null +++ b/include/media/si476x.h @@ -0,0 +1,426 @@ +/* + * include/media/si476x.h -- Common definitions for si476x driver + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 SI476X_H +#define SI476X_H + +#include +#include + +struct si476x_device; + +/* It is possible to select one of the four adresses using pins A0 + * and A1 on SI476x */ +#define SI476X_I2C_ADDR_1 0x60 +#define SI476X_I2C_ADDR_2 0x61 +#define SI476X_I2C_ADDR_3 0x62 +#define SI476X_I2C_ADDR_4 0x63 + +enum si476x_iqclk_config { + SI476X_IQCLK_NOOP = 0, + SI476X_IQCLK_TRISTATE = 1, + SI476X_IQCLK_IQ = 21, +}; +enum si476x_iqfs_config { + SI476X_IQFS_NOOP = 0, + SI476X_IQFS_TRISTATE = 1, + SI476X_IQFS_IQ = 21, +}; +enum si476x_iout_config { + SI476X_IOUT_NOOP = 0, + SI476X_IOUT_TRISTATE = 1, + SI476X_IOUT_OUTPUT = 22, +}; +enum si476x_qout_config { + SI476X_QOUT_NOOP = 0, + SI476X_QOUT_TRISTATE = 1, + SI476X_QOUT_OUTPUT = 22, +}; + +enum si476x_dclk_config { + SI476X_DCLK_NOOP = 0, + SI476X_DCLK_TRISTATE = 1, + SI476X_DCLK_DAUDIO = 10, +}; + +enum si476x_dfs_config { + SI476X_DFS_NOOP = 0, + SI476X_DFS_TRISTATE = 1, + SI476X_DFS_DAUDIO = 10, +}; + +enum si476x_dout_config { + SI476X_DOUT_NOOP = 0, + SI476X_DOUT_TRISTATE = 1, + SI476X_DOUT_I2S_OUTPUT = 12, + SI476X_DOUT_I2S_INPUT = 13, +}; + +enum si476x_xout_config { + SI476X_XOUT_NOOP = 0, + SI476X_XOUT_TRISTATE = 1, + SI476X_XOUT_I2S_INPUT = 13, + SI476X_XOUT_MODE_SELECT = 23, +}; + + +enum si476x_icin_config { + SI476X_ICIN_NOOP = 0, + SI476X_ICIN_TRISTATE = 1, + SI476X_ICIN_GPO1_HIGH = 2, + SI476X_ICIN_GPO1_LOW = 3, + SI476X_ICIN_IC_LINK = 30, +}; + +enum si476x_icip_config { + SI476X_ICIP_NOOP = 0, + SI476X_ICIP_TRISTATE = 1, + SI476X_ICIP_GPO2_HIGH = 2, + SI476X_ICIP_GPO2_LOW = 3, + SI476X_ICIP_IC_LINK = 30, +}; + +enum si476x_icon_config { + SI476X_ICON_NOOP = 0, + SI476X_ICON_TRISTATE = 1, + SI476X_ICON_I2S = 10, + SI476X_ICON_IC_LINK = 30, +}; + +enum si476x_icop_config { + SI476X_ICOP_NOOP = 0, + SI476X_ICOP_TRISTATE = 1, + SI476X_ICOP_I2S = 10, + SI476X_ICOP_IC_LINK = 30, +}; + + +enum si476x_lrout_config { + SI476X_LROUT_NOOP = 0, + SI476X_LROUT_TRISTATE = 1, + SI476X_LROUT_AUDIO = 2, + SI476X_LROUT_MPX = 3, +}; + + +enum si476x_intb_config { + SI476X_INTB_NOOP = 0, + SI476X_INTB_TRISTATE = 1, + SI476X_INTB_DAUDIO = 10, + SI476X_INTB_IRQ = 40, +}; + +enum si476x_a1_config { + SI476X_A1_NOOP = 0, + SI476X_A1_TRISTATE = 1, + SI476X_A1_IRQ = 40, +}; + +enum si476x_part_revisions { + SI476X_REVISION_A10 = 0, + SI476X_REVISION_A20 = 1, + SI476X_REVISION_A30 = 2, +}; + +struct si476x_pinmux { + enum si476x_dclk_config dclk; + enum si476x_dfs_config dfs; + enum si476x_dout_config dout; + enum si476x_xout_config xout; + + enum si476x_iqclk_config iqclk; + enum si476x_iqfs_config iqfs; + enum si476x_iout_config iout; + enum si476x_qout_config qout; + + enum si476x_icin_config icin; + enum si476x_icip_config icip; + enum si476x_icon_config icon; + enum si476x_icop_config icop; + + enum si476x_lrout_config lrout; + + enum si476x_intb_config intb; + enum si476x_a1_config a1; +}; + +/** + * enum si476x_phase_diversity_mode - possbile phase diversity modes + * for SI4764/5/6/7 chips. + * + * @SI476X_PHDIV_DISABLED: Phase diversity feature is + * disabled. + * @SI476X_PHDIV_PRIMARY_COMBINING: Tuner works as a primary tuner + * in combination with a + * secondary one. + * @SI476X_PHDIV_PRIMARY_ANTENNA: Tuner works as a primary tuner + * using only its own antenna. + * @SI476X_PHDIV_SECONDARY_ANTENNA: Tuner works as a primary tuner + * usning seconary tuner's antenna. + * @SI476X_PHDIV_SECONDARY_COMBINING: Tuner works as a secondary + * tuner in combination with the + * primary one. + */ +enum si476x_phase_diversity_mode { + SI476X_PHDIV_DISABLED = 0, + SI476X_PHDIV_PRIMARY_COMBINING = 1, + SI476X_PHDIV_PRIMARY_ANTENNA = 2, + SI476X_PHDIV_SECONDARY_ANTENNA = 3, + SI476X_PHDIV_SECONDARY_COMBINING = 5, +}; + +enum si476x_ibias6x { + SI476X_IBIAS6X_OTHER = 0, + SI476X_IBIAS6X_RCVR1_NON_4MHZ_CLK = 1, +}; + +enum si476x_xstart { + SI476X_XSTART_MULTIPLE_TUNER = 0x11, + SI476X_XSTART_NORMAL = 0x77, +}; + +enum si476x_freq { + SI476X_FREQ_4_MHZ = 0, + SI476X_FREQ_37P209375_MHZ = 1, + SI476X_FREQ_36P4_MHZ = 2, + SI476X_FREQ_37P8_MHZ = 3, +}; + +enum si476x_xmode { + SI476X_XMODE_CRYSTAL_RCVR1 = 1, + SI476X_XMODE_EXT_CLOCK = 2, + SI476X_XMODE_CRYSTAL_RCVR2_3 = 3, +}; + +enum si476x_xbiashc { + SI476X_XBIASHC_SINGLE_RECEIVER = 0, + SI476X_XBIASHC_MULTIPLE_RECEIVER = 1, +}; + +enum si476x_xbias { + SI476X_XBIAS_RCVR2_3 = 0, + SI476X_XBIAS_4MHZ_RCVR1 = 3, + SI476X_XBIAS_RCVR1 = 7, +}; + +enum si476x_func { + SI476X_FUNC_BOOTLOADER = 0, + SI476X_FUNC_FM_RECEIVER = 1, + SI476X_FUNC_AM_RECEIVER = 2, + SI476X_FUNC_WB_RECEIVER = 3, +}; + + +/** + * @xcload: Selects the amount of additional on-chip capacitance to + * be connected between XTAL1 and gnd and between XTAL2 and + * GND. One half of the capacitance value shown here is the + * additional load capacitance presented to the xtal. The + * minimum step size is 0.277 pF. Recommended value is 0x28 + * but it will be layout dependent. Range is 0–0x3F i.e. + * (0–16.33 pF) + * @ctsien: enable CTSINT(interrupt request when CTS condition + * arises) when set + * @intsel: when set A1 pin becomes the interrupt pin; otherwise, + * INTB is the interrupt pin + * @func: selects the boot function of the device. I.e. + * SI476X_BOOTLOADER - Boot loader + * SI476X_FM_RECEIVER - FM receiver + * SI476X_AM_RECEIVER - AM receiver + * SI476X_WB_RECEIVER - Weatherband receiver + * @freq: oscillator's crystal frequency: + * SI476X_XTAL_37P209375_MHZ - 37.209375 Mhz + * SI476X_XTAL_36P4_MHZ - 36.4 Mhz + * SI476X_XTAL_37P8_MHZ - 37.8 Mhz + */ +struct si476x_power_up_args { + enum si476x_ibias6x ibias6x; + enum si476x_xstart xstart; + u8 xcload; + bool fastboot; + enum si476x_xbiashc xbiashc; + enum si476x_xbias xbias; + enum si476x_func func; + enum si476x_freq freq; + enum si476x_xmode xmode; +}; + + +enum si476x_ctrl_id { + V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1), + V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2), + V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3), + V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4), + V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5), + V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6), +}; + +/* + * Platform dependent definition + */ +struct si476x_platform_data { + int gpio_reset; /* < 0 if not used */ + + struct si476x_power_up_args power_up_parameters; + enum si476x_phase_diversity_mode diversity_mode; + + struct si476x_pinmux pinmux; +}; + +/** + * struct si476x_rsq_status - structure containing received signal + * quality + * @multhint: Multipath Detect High. + * true - Indicatedes that the value is below + * FM_RSQ_MULTIPATH_HIGH_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_MULTIPATH_HIGH_THRESHOLD + * @multlint: Multipath Detect Low. + * true - Indicatedes that the value is below + * FM_RSQ_MULTIPATH_LOW_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_MULTIPATH_LOW_THRESHOLD + * @snrhint: SNR Detect High. + * true - Indicatedes that the value is below + * FM_RSQ_SNR_HIGH_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_SNR_HIGH_THRESHOLD + * @snrlint: SNR Detect Low. + * true - Indicatedes that the value is below + * FM_RSQ_SNR_LOW_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_SNR_LOW_THRESHOLD + * @rssihint: RSSI Detect High. + * true - Indicatedes that the value is below + * FM_RSQ_RSSI_HIGH_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_RSSI_HIGH_THRESHOLD + * @rssilint: RSSI Detect Low. + * true - Indicatedes that the value is below + * FM_RSQ_RSSI_LOW_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_RSSI_LOW_THRESHOLD + * @bltf: Band Limit. + * Set if seek command hits the band limit or wrapped to + * the original frequency. + * @snr_ready: SNR measurement in progress. + * @rssiready: RSSI measurement in progress. + * @afcrl: Set if FREQOFF >= MAX_TUNE_ERROR + * @valid: Set if the channel is valid + * rssi < FM_VALID_RSSI_THRESHOLD + * snr < FM_VALID_SNR_THRESHOLD + * tune_error < FM_VALID_MAX_TUNE_ERROR + * @readfreq: Current tuned frequency. + * @freqoff: Signed frequency offset. + * @rssi: Received Signal Strength Indicator(dBuV). + * @snr: RF SNR Indicator(dB). + * @lassi: + * @hassi: Low/High side Adjacent(100 kHz) Channel Strength Indicator + * @mult: Multipath indicator + * @dev: Who knows? But values may vary. + * @readantcap: Antenna tuning capacity value. + * @assi: Adjacent Channel(+/- 200kHz) Strength Indicator + * @usn: Ultrasonic Noise Inticator in -DBFS + */ +struct si476x_rsq_status_report { + __u8 multhint, multlint; + __u8 snrhint, snrlint; + __u8 rssihint, rssilint; + __u8 bltf; + __u8 snr_ready; + __u8 rssiready; + __u8 injside; + __u8 afcrl; + __u8 valid; + + __u16 readfreq; + __s8 freqoff; + __s8 rssi; + __s8 snr; + __s8 issi; + __s8 lassi, hassi; + __s8 mult; + __u8 dev; + __u16 readantcap; + __s8 assi; + __s8 usn; + + __u8 pilotdev; + __u8 rdsdev; + __u8 assidev; + __u8 strongdev; + __u16 rdspi; +} __packed; + +/** + * si476x_acf_status_report - ACF report results + * + * @blend_int: If set, indicates that stereo separation has crossed + * below the blend threshold as set by FM_ACF_BLEND_THRESHOLD + * @hblend_int: If set, indicates that HiBlend cutoff frequency is + * lower than threshold as set by FM_ACF_HBLEND_THRESHOLD + * @hicut_int: If set, indicates that HiCut cutoff frequency is lower + * than the threshold set by ACF_ + + */ +struct si476x_acf_status_report { + __u8 blend_int; + __u8 hblend_int; + __u8 hicut_int; + __u8 chbw_int; + __u8 softmute_int; + __u8 smute; + __u8 smattn; + __u8 chbw; + __u8 hicut; + __u8 hiblend; + __u8 pilot; + __u8 stblend; +} __packed; + +enum si476x_fmagc { + SI476X_FMAGC_10K_OHM = 0, + SI476X_FMAGC_800_OHM = 1, + SI476X_FMAGC_400_OHM = 2, + SI476X_FMAGC_200_OHM = 4, + SI476X_FMAGC_100_OHM = 8, + SI476X_FMAGC_50_OHM = 16, + SI476X_FMAGC_25_OHM = 32, + SI476X_FMAGC_12P5_OHM = 64, + SI476X_FMAGC_6P25_OHM = 128, +}; + +struct si476x_agc_status_report { + __u8 mxhi; + __u8 mxlo; + __u8 lnahi; + __u8 lnalo; + __u8 fmagc1; + __u8 fmagc2; + __u8 pgagain; + __u8 fmwblang; +} __packed; + +struct si476x_rds_blockcount_report { + __u16 expected; + __u16 received; + __u16 uncorrectable; +} __packed; + +#endif /* SI476X_H*/ -- cgit v1.2.3 From 2cb5972da8ee95c58db3375c288563f3b75bc61c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 29 Mar 2013 10:14:32 -0300 Subject: [media] v4l2-controls.h: update private control ranges to prevent overlap These ranges shouldn't overlap. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-controls.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 910d7cd3d9f4..7da22cec30cd 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -153,12 +153,12 @@ enum v4l2_colorfx { /* The base for the s2255 driver controls. - * We reserve 8 controls for this driver. */ -#define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1010) + * We reserve 16 controls for this driver. */ +#define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1030) /* The base for the si476x driver controls. See include/media/si476x.h for the list - * of controls. Total of 16 controls is reserved for that driver */ -#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1010) + * of controls. Total of 16 controls is reserved for this driver */ +#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1040) /* MPEG-class control IDs */ -- cgit v1.2.3 From 99fd133f907afdb430942d8d2ae53faa438adfe8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 26 Sep 2012 05:24:03 -0300 Subject: [media] Add a V4L2 OF parser Add a V4L2 OF parser, implementing bindings documented in Documentation/devicetree/bindings/media/video-interfaces.txt. [s.nawrocki@samsung.com: various corrections and improvements since the initial version] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/Makefile | 3 + drivers/media/v4l2-core/v4l2-of.c | 267 ++++++++++++++++++++++++++++++++++++++ include/media/v4l2-of.h | 111 ++++++++++++++++ 3 files changed, 381 insertions(+) create mode 100644 drivers/media/v4l2-core/v4l2-of.c create mode 100644 include/media/v4l2-of.h (limited to 'include') diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index a9d355230e8e..00c4a1993d58 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -9,6 +9,9 @@ videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ ifeq ($(CONFIG_COMPAT),y) videodev-objs += v4l2-compat-ioctl32.o endif +ifeq ($(CONFIG_OF),y) + videodev-objs += v4l2-of.o +endif obj-$(CONFIG_VIDEO_DEV) += videodev.o obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c new file mode 100644 index 000000000000..e38e21064b5f --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -0,0 +1,267 @@ +/* + * V4L2 OF binding parsing library + * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * Copyright (C) 2012 Renesas Electronics Corp. + * Author: Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include + +static void v4l2_of_parse_csi_bus(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) +{ + struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2; + u32 data_lanes[ARRAY_SIZE(bus->data_lanes)]; + struct property *prop; + bool have_clk_lane = false; + unsigned int flags = 0; + u32 v; + + prop = of_find_property(node, "data-lanes", NULL); + if (prop) { + const __be32 *lane = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(data_lanes); i++) { + lane = of_prop_next_u32(prop, lane, &data_lanes[i]); + if (!lane) + break; + } + bus->num_data_lanes = i; + while (i--) + bus->data_lanes[i] = data_lanes[i]; + } + + if (!of_property_read_u32(node, "clock-lanes", &v)) { + bus->clock_lane = v; + have_clk_lane = true; + } + + if (of_get_property(node, "clock-noncontinuous", &v)) + flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; + else if (have_clk_lane || bus->num_data_lanes > 0) + flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + bus->flags = flags; + endpoint->bus_type = V4L2_MBUS_CSI2; +} + +static void v4l2_of_parse_parallel_bus(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) +{ + struct v4l2_of_bus_parallel *bus = &endpoint->bus.parallel; + unsigned int flags = 0; + u32 v; + + if (!of_property_read_u32(node, "hsync-active", &v)) + flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH : + V4L2_MBUS_HSYNC_ACTIVE_LOW; + + if (!of_property_read_u32(node, "vsync-active", &v)) + 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; + if (flags) + endpoint->bus_type = V4L2_MBUS_PARALLEL; + else + endpoint->bus_type = V4L2_MBUS_BT656; + + if (!of_property_read_u32(node, "data-active", &v)) + flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH : + V4L2_MBUS_DATA_ACTIVE_LOW; + + if (of_get_property(node, "slave-mode", &v)) + flags |= V4L2_MBUS_SLAVE; + else + flags |= V4L2_MBUS_MASTER; + + if (!of_property_read_u32(node, "bus-width", &v)) + bus->bus_width = v; + + if (!of_property_read_u32(node, "data-shift", &v)) + bus->data_shift = v; + + bus->flags = flags; + +} +EXPORT_SYMBOL(v4l2_of_parse_parallel_bus); + +/** + * v4l2_of_parse_endpoint() - parse all endpoint node properties + * @node: pointer to endpoint device_node + * @endpoint: pointer to the V4L2 OF endpoint data structure + * + * 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. + */ +void v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) +{ + struct device_node *port_node = of_get_parent(node); + + memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head)); + + endpoint->local_node = node; + /* + * It doesn't matter whether the two calls below succeed. + * If they don't then the default value 0 is used. + */ + of_property_read_u32(port_node, "reg", &endpoint->port); + of_property_read_u32(node, "reg", &endpoint->id); + + v4l2_of_parse_csi_bus(node, endpoint); + /* + * Parse the parallel video bus properties only if none + * of the MIPI CSI-2 specific properties were found. + */ + if (endpoint->bus.mipi_csi2.flags == 0) + v4l2_of_parse_parallel_bus(node, endpoint); + + of_node_put(port_node); +} +EXPORT_SYMBOL(v4l2_of_parse_endpoint); + +/** + * v4l2_of_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is not decremented, the caller have to use + * of_node_put() on it when done. + */ +struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *endpoint; + struct device_node *port = NULL; + + if (!parent) + return NULL; + + if (!prev) { + struct device_node *node; + /* + * It's the first call, we have to find a port subnode + * within this node or within an optional 'ports' node. + */ + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + for_each_child_of_node(parent, node) { + if (!of_node_cmp(node->name, "port")) { + port = node; + break; + } + } + if (port) { + /* Found a port, get an endpoint. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + } else { + endpoint = NULL; + } + + if (!endpoint) + pr_err("%s(): no endpoint nodes specified for %s\n", + __func__, parent->full_name); + } else { + port = of_get_parent(prev); + if (!port) + /* Hm, has someone given us the root node ?... */ + return NULL; + + /* Avoid dropping prev node refcount to 0. */ + of_node_get(prev); + endpoint = of_get_next_child(port, prev); + if (endpoint) { + of_node_put(port); + return endpoint; + } + + /* No more endpoints under this port, try the next one. */ + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + + /* Pick up the first endpoint in this port. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + } + + return endpoint; +} +EXPORT_SYMBOL(v4l2_of_get_next_endpoint); + +/** + * v4l2_of_get_remote_port_parent() - get remote port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: Remote device node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *v4l2_of_get_remote_port_parent( + const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = of_get_next_parent(np); + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} +EXPORT_SYMBOL(v4l2_of_get_remote_port_parent); + +/** + * v4l2_of_get_remote_port() - get remote port node + * @node: pointer to a local endpoint device_node + * + * Return: Remote port node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *v4l2_of_get_remote_port(const struct device_node *node) +{ + struct device_node *np; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) + return NULL; + return of_get_parent(np); +} +EXPORT_SYMBOL(v4l2_of_get_remote_port); diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h new file mode 100644 index 000000000000..00f91473498c --- /dev/null +++ b/include/media/v4l2-of.h @@ -0,0 +1,111 @@ +/* + * V4L2 OF binding parsing library + * + * Copyright (C) 2012 Renesas Electronics Corp. + * Author: Guennadi Liakhovetski + * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + */ +#ifndef _V4L2_OF_H +#define _V4L2_OF_H + +#include +#include +#include + +#include + +struct device_node; + +/** + * struct v4l2_of_bus_mipi_csi2 - MIPI CSI-2 bus data structure + * @flags: media bus (V4L2_MBUS_*) flags + * @data_lanes: an array of physical data lane indexes + * @clock_lane: physical lane index of the clock lane + * @num_data_lanes: number of data lanes + */ +struct v4l2_of_bus_mipi_csi2 { + unsigned int flags; + unsigned char data_lanes[4]; + unsigned char clock_lane; + unsigned short num_data_lanes; +}; + +/** + * struct v4l2_of_bus_parallel - parallel data bus data structure + * @flags: media bus (V4L2_MBUS_*) flags + * @bus_width: bus width in bits + * @data_shift: data shift in bits + */ +struct v4l2_of_bus_parallel { + unsigned int flags; + unsigned char bus_width; + unsigned char data_shift; +}; + +/** + * struct v4l2_of_endpoint - the endpoint data structure + * @port: identifier (value of reg property) of a port this endpoint belongs to + * @id: identifier (value of reg property) of this endpoint + * @local_node: pointer to device_node of this endpoint + * @remote: phandle to remote endpoint node + * @bus_type: bus type + * @bus: bus configuration data structure + * @head: list head for this structure + */ +struct v4l2_of_endpoint { + unsigned int port; + unsigned int id; + const struct device_node *local_node; + const __be32 *remote; + enum v4l2_mbus_type bus_type; + union { + struct v4l2_of_bus_parallel parallel; + struct v4l2_of_bus_mipi_csi2 mipi_csi2; + } bus; + struct list_head head; +}; + +#ifdef CONFIG_OF +void v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *link); +struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, + struct device_node *previous); +struct device_node *v4l2_of_get_remote_port_parent( + const struct device_node *node); +struct device_node *v4l2_of_get_remote_port(const struct device_node *node); +#else /* CONFIG_OF */ + +static inline int v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *link) +{ + return -ENOSYS; +} + +static inline struct device_node *v4l2_of_get_next_endpoint( + const struct device_node *parent, + struct device_node *previous) +{ + return NULL; +} + +static inline struct device_node *v4l2_of_get_remote_port_parent( + const struct device_node *node) +{ + return NULL; +} + +static inline struct device_node *v4l2_of_get_remote_port( + const struct device_node *node) +{ + return NULL; +} + +#endif /* CONFIG_OF */ + +#endif /* _V4L2_OF_H */ -- cgit v1.2.3 From 02399e35e6bb716ce9636eba006b792362270034 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Mar 2013 08:20:30 -0300 Subject: [media] s5p-csis: Add device tree support This patch support for binding the driver to the MIPI-CSIS devices instantiated from device tree and parsing the SoC and board specific properties. The MIPI CSI-2 channel is determined by the value of reg property placed in csis' port subnode. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/samsung-mipi-csis.txt | 81 +++++++++++ drivers/media/platform/s5p-fimc/mipi-csis.c | 155 ++++++++++++++++----- drivers/media/platform/s5p-fimc/mipi-csis.h | 1 + include/media/s5p_fimc.h | 13 ++ 4 files changed, 215 insertions(+), 35 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/samsung-mipi-csis.txt (limited to 'include') diff --git a/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt new file mode 100644 index 000000000000..5f8e28e2484f --- /dev/null +++ b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt @@ -0,0 +1,81 @@ +Samsung S5P/EXYNOS SoC series MIPI CSI-2 receiver (MIPI CSIS) +------------------------------------------------------------- + +Required properties: + +- compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110), + "samsung,exynos4210-csis" for Exynos4210 (S5PC210), + "samsung,exynos4212-csis" for Exynos4212/Exynos4412 + SoC series; +- reg : offset and length of the register set for the device; +- interrupts : should contain MIPI CSIS interrupt; the format of the + interrupt specifier depends on the interrupt controller; +- bus-width : maximum number of data lanes supported (SoC specific); +- vddio-supply : MIPI CSIS I/O and PLL voltage supply (e.g. 1.8V); +- vddcore-supply : MIPI CSIS Core voltage supply (e.g. 1.1V); +- clocks : list of clock specifiers, corresponding to entries in + clock-names property; +- clock-names : must contain "csis", "sclk_csis" entries, matching entries + in the clocks property. + +Optional properties: + +- clock-frequency : The IP's main (system bus) clock frequency in Hz, default + value when this property is not specified is 166 MHz; +- samsung,csis-wclk : CSI-2 wrapper clock selection. If this property is present + external clock from CMU will be used, or the bus clock if + if it's not specified. + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +media/video-interfaces.txt. The following are properties specific to those nodes. + +port node +--------- + +- reg : (required) must be 3 for camera C input (CSIS0) or 4 for + camera D input (CSIS1); + +endpoint node +------------- + +- data-lanes : (required) an array specifying active physical MIPI-CSI2 + data input lanes and their mapping to logical lanes; the + array's content is unused, only its length is meaningful; + +- samsung,csis-hs-settle : (optional) differential receiver (HS-RX) settle time; + + +Example: + + reg0: regulator@0 { + }; + + reg1: regulator@1 { + }; + +/* SoC properties */ + + csis_0: csis@11880000 { + compatible = "samsung,exynos4210-csis"; + reg = <0x11880000 0x1000>; + interrupts = <0 78 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + +/* Board properties */ + + csis_0: csis@11880000 { + clock-frequency = <166000000>; + vddio-supply = <®0>; + vddcore-supply = <®1>; + port { + reg = <3>; /* 3 - CSIS0, 4 - CSIS1 */ + csis0_ep: endpoint { + remote-endpoint = <...>; + data-lanes = <1>, <2>; + samsung,csis-hs-settle = <12>; + }; + }; + }; diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index 981863d05aaa..8636bcddde1b 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -19,14 +19,18 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include +#include #include -#include + #include "mipi-csis.h" static int debug; @@ -113,6 +117,7 @@ static char *csi_clock_name[] = { [CSIS_CLK_GATE] = "csis", }; #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) +#define DEFAULT_SCLK_CSIS_FREQ 166000000UL static const char * const csis_supply_name[] = { "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ @@ -167,6 +172,11 @@ struct csis_pktbuf { * @clock: CSIS clocks * @irq: requested s5p-mipi-csis irq number * @flags: the state variable for power and streaming control + * @clock_frequency: device bus clock frequency + * @hs_settle: HS-RX settle time + * @num_lanes: number of MIPI-CSI data lanes used + * @max_num_lanes: maximum number of MIPI-CSI data lanes supported + * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM * @csis_fmt: current CSIS pixel format * @format: common media bus format for the source and sink pad * @slock: spinlock protecting structure members below @@ -184,6 +194,13 @@ struct csis_state { struct clk *clock[NUM_CSIS_CLOCKS]; int irq; u32 flags; + + u32 clk_frequency; + u32 hs_settle; + u32 num_lanes; + u32 max_num_lanes; + u8 wclk_ext; + const struct csis_pix_format *csis_fmt; struct v4l2_mbus_framefmt format; @@ -273,7 +290,6 @@ static void s5pcsis_reset(struct csis_state *state) static void s5pcsis_system_enable(struct csis_state *state, int on) { - struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data; u32 val, mask; val = s5pcsis_read(state, S5PCSIS_CTRL); @@ -286,7 +302,7 @@ static void s5pcsis_system_enable(struct csis_state *state, int on) val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); val &= ~S5PCSIS_DPHYCTRL_ENABLE; if (on) { - mask = (1 << (pdata->lanes + 1)) - 1; + mask = (1 << (state->num_lanes + 1)) - 1; val |= (mask & S5PCSIS_DPHYCTRL_ENABLE); } s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); @@ -321,15 +337,14 @@ static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle) static void s5pcsis_set_params(struct csis_state *state) { - struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data; u32 val; val = s5pcsis_read(state, S5PCSIS_CONFIG); - val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1); + val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (state->num_lanes - 1); s5pcsis_write(state, S5PCSIS_CONFIG, val); __s5pcsis_set_format(state); - s5pcsis_set_hsync_settle(state, pdata->hs_settle); + s5pcsis_set_hsync_settle(state, state->hs_settle); val = s5pcsis_read(state, S5PCSIS_CTRL); if (state->csis_fmt->data_alignment == 32) @@ -338,7 +353,7 @@ static void s5pcsis_set_params(struct csis_state *state) val &= ~S5PCSIS_CTRL_ALIGN_32BIT; val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; - if (pdata->wclk_source) + if (state->wclk_ext) val |= S5PCSIS_CTRL_WCLK_EXTCLK; s5pcsis_write(state, S5PCSIS_CTRL, val); @@ -701,52 +716,111 @@ static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int s5pcsis_get_platform_data(struct platform_device *pdev, + struct csis_state *state) +{ + struct s5p_platform_mipi_csis *pdata = pdev->dev.platform_data; + + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform data not specified\n"); + return -EINVAL; + } + + state->clk_frequency = pdata->clk_rate; + state->num_lanes = pdata->lanes; + state->hs_settle = pdata->hs_settle; + state->index = max(0, pdev->id); + state->max_num_lanes = state->index ? CSIS1_MAX_LANES : + CSIS0_MAX_LANES; + return 0; +} + +#ifdef CONFIG_OF +static int s5pcsis_parse_dt(struct platform_device *pdev, + struct csis_state *state) +{ + struct device_node *node = pdev->dev.of_node; + struct v4l2_of_endpoint endpoint; + + if (of_property_read_u32(node, "clock-frequency", + &state->clk_frequency)) + state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + if (of_property_read_u32(node, "bus-width", + &state->max_num_lanes)) + return -EINVAL; + + node = v4l2_of_get_next_endpoint(node, NULL); + if (!node) { + dev_err(&pdev->dev, "No port node at %s\n", + node->full_name); + return -EINVAL; + } + /* Get port node and validate MIPI-CSI channel id. */ + v4l2_of_parse_endpoint(node, &endpoint); + + state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0; + if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) + return -ENXIO; + + /* Get MIPI CSI-2 bus configration from the endpoint node. */ + of_property_read_u32(node, "samsung,csis-hs-settle", + &state->hs_settle); + state->wclk_ext = of_property_read_bool(node, + "samsung,csis-wclk"); + + state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes; + + of_node_put(node); + return 0; +} +#else +#define s5pcsis_parse_dt(pdev, state) (-ENOSYS) +#endif + static int s5pcsis_probe(struct platform_device *pdev) { - struct s5p_platform_mipi_csis *pdata; + struct device *dev = &pdev->dev; struct resource *mem_res; struct csis_state *state; int ret = -ENOMEM; int i; - state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; mutex_init(&state->lock); spin_lock_init(&state->slock); - state->pdev = pdev; - state->index = max(0, pdev->id); - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "Platform data not fully specified\n"); - return -EINVAL; - } + if (dev->of_node) + ret = s5pcsis_parse_dt(pdev, state); + else + ret = s5pcsis_get_platform_data(pdev, state); + if (ret < 0) + return ret; - if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) || - pdata->lanes > CSIS0_MAX_LANES) { - dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", - pdata->lanes); + if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) { + dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n", + state->num_lanes, state->max_num_lanes); return -EINVAL; } mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - state->regs = devm_ioremap_resource(&pdev->dev, mem_res); + state->regs = devm_ioremap_resource(dev, mem_res); if (IS_ERR(state->regs)) return PTR_ERR(state->regs); state->irq = platform_get_irq(pdev, 0); if (state->irq < 0) { - dev_err(&pdev->dev, "Failed to get irq\n"); + dev_err(dev, "Failed to get irq\n"); return state->irq; } for (i = 0; i < CSIS_NUM_SUPPLIES; i++) state->supplies[i].supply = csis_supply_name[i]; - ret = devm_regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, + ret = devm_regulator_bulk_get(dev, CSIS_NUM_SUPPLIES, state->supplies); if (ret) return ret; @@ -755,11 +829,11 @@ static int s5pcsis_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (pdata->clk_rate) + if (state->clk_frequency) ret = clk_set_rate(state->clock[CSIS_CLK_MUX], - pdata->clk_rate); + state->clk_frequency); else - dev_WARN(&pdev->dev, "No clock frequency specified!\n"); + dev_WARN(dev, "No clock frequency specified!\n"); if (ret < 0) goto e_clkput; @@ -767,16 +841,17 @@ static int s5pcsis_probe(struct platform_device *pdev) if (ret < 0) goto e_clkput; - ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, - 0, dev_name(&pdev->dev), state); + ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler, + 0, dev_name(dev), state); if (ret) { - dev_err(&pdev->dev, "Interrupt request failed\n"); + dev_err(dev, "Interrupt request failed\n"); goto e_clkdis; } v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); state->sd.owner = THIS_MODULE; - strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name)); + snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d", + CSIS_SUBDEV_NAME, state->index); state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; state->csis_fmt = &s5pcsis_formats[0]; @@ -796,10 +871,12 @@ static int s5pcsis_probe(struct platform_device *pdev) /* .. and a pointer to the subdev. */ platform_set_drvdata(pdev, &state->sd); - memcpy(state->events, s5pcsis_events, sizeof(state->events)); + pm_runtime_enable(dev); - pm_runtime_enable(&pdev->dev); + dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", + state->num_lanes, state->hs_settle, state->wclk_ext, + state->clk_frequency); return 0; e_clkdis: @@ -923,13 +1000,21 @@ static const struct dev_pm_ops s5pcsis_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) }; +static const struct of_device_id s5pcsis_of_match[] = { + { .compatible = "samsung,s5pv210-csis" }, + { .compatible = "samsung,exynos4210-csis" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, s5pcsis_of_match); + static struct platform_driver s5pcsis_driver = { .probe = s5pcsis_probe, .remove = s5pcsis_remove, .driver = { - .name = CSIS_DRIVER_NAME, - .owner = THIS_MODULE, - .pm = &s5pcsis_pm_ops, + .of_match_table = s5pcsis_of_match, + .name = CSIS_DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &s5pcsis_pm_ops, }, }; diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.h b/drivers/media/platform/s5p-fimc/mipi-csis.h index 2709286396e1..28c11c4085d8 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.h +++ b/drivers/media/platform/s5p-fimc/mipi-csis.h @@ -11,6 +11,7 @@ #define S5P_MIPI_CSIS_H_ #define CSIS_DRIVER_NAME "s5p-mipi-csis" +#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME #define CSIS_MAX_ENTITIES 2 #define CSIS0_MAX_LANES 4 #define CSIS1_MAX_LANES 2 diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 28f3590aa031..d6dbb791f423 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -14,6 +14,19 @@ #include +/* + * Enumeration of data inputs to the camera subsystem. + */ +enum fimc_input { + FIMC_INPUT_PARALLEL_0 = 1, + FIMC_INPUT_PARALLEL_1, + FIMC_INPUT_MIPI_CSI2_0 = 3, + FIMC_INPUT_MIPI_CSI2_1, + FIMC_INPUT_WRITEBACK_A = 5, + FIMC_INPUT_WRITEBACK_B, + FIMC_INPUT_WRITEBACK_ISP = 5, +}; + /* * Enumeration of the FIMC data bus types. */ -- cgit v1.2.3 From e2985a260e6615503b4fa8e66788708e750c7750 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Mar 2013 12:59:33 -0300 Subject: [media] s5p-fimc: Add device tree support for the media device driver This patch adds changes required for the main camera media device driver corresponding to the top level 'camera' device node. The drivers of devices corresponding to child nodes of the 'camera' node are looked up and and registered as sub-devices to the top level driver. The main driver's probing is deferred if any of the sub-device drivers is not yet initialized and ready. Signed-off-by: Sylwester Nawrocki Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-core.c | 1 - drivers/media/platform/s5p-fimc/fimc-mdevice.c | 108 +++++++++++++++++++++---- drivers/media/platform/s5p-fimc/fimc-mdevice.h | 5 ++ include/media/s5p_fimc.h | 1 + 4 files changed, 98 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index d39e47abb229..6a8098c42cc8 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -1281,7 +1281,6 @@ static const struct platform_device_id fimc_driver_ids[] = { }, { }, }; -MODULE_DEVICE_TABLE(platform, fimc_driver_ids); static const struct of_device_id fimc_of_match[] = { { diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index a17fcb2d5d41..d34106c66427 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -17,11 +17,16 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include +#include #include #include @@ -264,6 +269,21 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) i2c_put_adapter(adapter); } +#ifdef CONFIG_OF +static int __of_get_csis_id(struct device_node *np) +{ + u32 reg = 0; + + np = of_get_child_by_name(np, "port"); + if (!np) + return -EINVAL; + of_property_read_u32(np, "reg", ®); + return reg - FIMC_INPUT_MIPI_CSI2_0; +} +#else +#define __of_get_csis_id(np) (-ENOSYS) +#endif + static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; @@ -368,13 +388,13 @@ static int register_csis_entity(struct fimc_md *fmd, struct device_node *node = pdev->dev.of_node; int id, ret; - id = node ? of_alias_get_id(node, "csis") : max(0, pdev->id); + id = node ? __of_get_csis_id(node) : max(0, pdev->id); - if (WARN_ON(id >= CSIS_MAX_ENTITIES || fmd->csis[id].sd)) - return -EBUSY; + if (WARN_ON(id < 0 || id >= CSIS_MAX_ENTITIES)) + return -ENOENT; - if (WARN_ON(id >= CSIS_MAX_ENTITIES)) - return 0; + if (WARN_ON(fmd->csis[id].sd)) + return -EBUSY; sd->grp_id = GRP_ID_CSIS; ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); @@ -457,6 +477,45 @@ static int fimc_md_pdev_match(struct device *dev, void *data) return 0; } +/* Register FIMC, FIMC-LITE and CSIS media entities */ +#ifdef CONFIG_OF +static int fimc_md_register_of_platform_entities(struct fimc_md *fmd, + struct device_node *parent) +{ + struct device_node *node; + int ret = 0; + + for_each_available_child_of_node(parent, node) { + struct platform_device *pdev; + int plat_entity = -1; + + pdev = of_find_device_by_node(node); + if (!pdev) + continue; + + /* If driver of any entity isn't ready try all again later. */ + if (!strcmp(node->name, CSIS_OF_NODE_NAME)) + plat_entity = IDX_CSIS; + else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME)) + plat_entity = IDX_FLITE; + else if (!strcmp(node->name, FIMC_OF_NODE_NAME) && + !of_property_read_bool(node, "samsung,lcd-wb")) + plat_entity = IDX_FIMC; + + if (plat_entity >= 0) + ret = fimc_md_register_platform_entity(fmd, pdev, + plat_entity); + put_device(&pdev->dev); + if (ret < 0) + break; + } + + return ret; +} +#else +#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS) +#endif + static void fimc_md_unregister_entities(struct fimc_md *fmd) { int i; @@ -929,11 +988,12 @@ static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, static int fimc_md_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct v4l2_device *v4l2_dev; struct fimc_md *fmd; int ret; - fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL); + fmd = devm_kzalloc(dev, sizeof(*fmd), GFP_KERNEL); if (!fmd) return -ENOMEM; @@ -943,15 +1003,14 @@ static int fimc_md_probe(struct platform_device *pdev) strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", sizeof(fmd->media_dev.model)); fmd->media_dev.link_notify = fimc_md_link_notify; - fmd->media_dev.dev = &pdev->dev; + fmd->media_dev.dev = dev; v4l2_dev = &fmd->v4l2_dev; v4l2_dev->mdev = &fmd->media_dev; v4l2_dev->notify = fimc_sensor_notify; - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s", - dev_name(&pdev->dev)); + strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name)); - ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); + ret = v4l2_device_register(dev, &fmd->v4l2_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); return ret; @@ -965,21 +1024,25 @@ static int fimc_md_probe(struct platform_device *pdev) if (ret) goto err_clk; - fmd->user_subdev_api = false; + fmd->user_subdev_api = (dev->of_node != NULL); /* Protect the media graph while we're registering entities */ mutex_lock(&fmd->media_dev.graph_mutex); - ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, - fimc_md_pdev_match); + if (dev->of_node) + ret = fimc_md_register_of_platform_entities(fmd, dev->of_node); + else + ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, + fimc_md_pdev_match); if (ret) goto err_unlock; - if (pdev->dev.platform_data) { + if (dev->platform_data) { ret = fimc_md_register_sensor_entities(fmd); if (ret) goto err_unlock; } + ret = fimc_md_create_links(fmd); if (ret) goto err_unlock; @@ -1019,12 +1082,25 @@ static int fimc_md_remove(struct platform_device *pdev) return 0; } +static struct platform_device_id fimc_driver_ids[] __always_unused = { + { .name = "s5p-fimc-md" }, + { }, +}; +MODULE_DEVICE_TABLE(platform, fimc_driver_ids); + +static const struct of_device_id fimc_md_of_match[] = { + { .compatible = "samsung,fimc" }, + { }, +}; +MODULE_DEVICE_TABLE(of, fimc_md_of_match); + static struct platform_driver fimc_md_driver = { .probe = fimc_md_probe, .remove = fimc_md_remove, .driver = { - .name = "s5p-fimc-md", - .owner = THIS_MODULE, + .of_match_table = of_match_ptr(fimc_md_of_match), + .name = "s5p-fimc-md", + .owner = THIS_MODULE, } }; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h index 06b0d8276fd2..b6ceb5984664 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h @@ -21,6 +21,11 @@ #include "fimc-lite.h" #include "mipi-csis.h" +#define FIMC_OF_NODE_NAME "fimc" +#define FIMC_LITE_OF_NODE_NAME "fimc-lite" +#define FIMC_IS_OF_NODE_NAME "fimc-is" +#define CSIS_OF_NODE_NAME "csis" + /* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ #define GRP_ID_SENSOR (1 << 8) #define GRP_ID_FIMC_IS_SENSOR (1 << 9) diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index d6dbb791f423..e2c598962698 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -94,6 +94,7 @@ enum fimc_subdev_index { IDX_SENSOR, IDX_CSIS, IDX_FLITE, + IDX_IS_ISP, IDX_FIMC, IDX_MAX, }; -- cgit v1.2.3 From 2b13f7d4e3822ed4de37b73b009ff81932e884bb Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 29 Mar 2013 14:12:39 -0300 Subject: [media] s5p-fimc: Add device tree based sensors registration The sensor (I2C and/or SPI client) devices are instantiated by their corresponding control bus drivers. Since the I2C client's master clock is often provided by a video bus receiver (host interface) or other than I2C/SPI controller device, the drivers of those client devices are not accessing hardware in their driver's probe() callback. Instead, after enabling clock, the host driver calls back into a sub-device when it wants to activate them. This pattern is used by some in-tree drivers and this patch also uses it for DT case. This patch is intended as a first step for adding device tree support to the S5P/Exynos SoC camera drivers. The second one is adding support for asynchronous sub-devices registration and clock control from sub-device driver level. The bindings shall not change when asynchronous probing support is added. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/samsung-fimc.txt | 86 ++++++++ drivers/media/platform/s5p-fimc/fimc-mdevice.c | 240 ++++++++++++++++++--- include/media/s5p_fimc.h | 3 + 3 files changed, 303 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt index 22e2889162c3..bcb0de7462a2 100644 --- a/Documentation/devicetree/bindings/media/samsung-fimc.txt +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt @@ -72,18 +72,95 @@ Optional properties: writeback input. +'parallel-ports' node +--------------------- + +This node should contain child 'port' nodes specifying active parallel video +input ports. It includes camera A and camera B inputs. 'reg' property in the +port nodes specifies data input - 0, 1 indicates input A, B respectively. + +Optional properties + +- samsung,camclk-out : specifies clock output for remote sensor, + 0 - CAM_A_CLKOUT, 1 - CAM_B_CLKOUT; + +Image sensor nodes +------------------ + +The sensor device nodes should be added to their control bus controller (e.g. +I2C0) nodes and linked to a port node in the csis or the parallel-ports node, +using the common video interfaces bindings, defined in video-interfaces.txt. +The implementation of this bindings requires clock-frequency property to be +present in the sensor device nodes. + Example: aliases { fimc0 = &fimc_0; }; + /* Parallel bus IF sensor */ + i2c_0: i2c@13860000 { + s5k6aa: sensor@3c { + compatible = "samsung,s5k6aafx"; + reg = <0x3c>; + vddio-supply = <...>; + + clock-frequency = <24000000>; + clocks = <...>; + clock-names = "mclk"; + + port { + s5k6aa_ep: endpoint { + remote-endpoint = <&fimc0_ep>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <1>; + pclk-sample = <1>; + }; + }; + }; + }; + + /* MIPI CSI-2 bus IF sensor */ + s5c73m3: sensor@0x1a { + compatible = "samsung,s5c73m3"; + reg = <0x1a>; + vddio-supply = <...>; + + clock-frequency = <24000000>; + clocks = <...>; + clock-names = "mclk"; + + port { + s5c73m3_1: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&csis0_ep>; + }; + }; + }; + camera { compatible = "samsung,fimc", "simple-bus"; #address-cells = <1>; #size-cells = <1>; status = "okay"; + /* parallel camera ports */ + parallel-ports { + /* camera A input */ + port@0 { + reg = <0>; + fimc0_ep: endpoint { + remote-endpoint = <&s5k6aa_ep>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <1>; + pclk-sample = <1>; + }; + }; + }; + fimc_0: fimc@11800000 { compatible = "samsung,exynos4210-fimc"; reg = <0x11800000 0x1000>; @@ -95,6 +172,15 @@ Example: compatible = "samsung,exynos4210-csis"; reg = <0x11880000 0x1000>; interrupts = <0 78 0>; + /* camera C input */ + port@3 { + reg = <3>; + csis0_ep: endpoint { + remote-endpoint = <&s5c73m3_ep>; + data-lanes = <1 2 3 4>; + samsung,csis-hs-settle = <12>; + }; + }; }; }; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index d34106c66427..bfa02abd94c8 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -251,7 +251,7 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, sd->grp_id = GRP_ID_SENSOR; v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n", - s_info->pdata.board_info->type); + sd->name); return sd; } @@ -263,13 +263,191 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) if (!client) return; v4l2_device_unregister_subdev(sd); - adapter = client->adapter; - i2c_unregister_device(client); - if (adapter) - i2c_put_adapter(adapter); + + if (!client->dev.of_node) { + adapter = client->adapter; + i2c_unregister_device(client); + if (adapter) + i2c_put_adapter(adapter); + } } #ifdef CONFIG_OF +/* Register I2C client subdev associated with @node. */ +static int fimc_md_of_add_sensor(struct fimc_md *fmd, + struct device_node *node, int index) +{ + struct fimc_sensor_info *si; + struct i2c_client *client; + struct v4l2_subdev *sd; + int ret; + + if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) + return -EINVAL; + si = &fmd->sensor[index]; + + client = of_find_i2c_device_by_node(node); + if (!client) + return -EPROBE_DEFER; + + device_lock(&client->dev); + + if (!client->driver || + !try_module_get(client->driver->driver.owner)) { + ret = -EPROBE_DEFER; + v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n", + node->full_name); + goto dev_put; + } + + /* Enable sensor's master clock */ + ret = __fimc_md_set_camclk(fmd, si, true); + if (ret < 0) + goto mod_put; + sd = i2c_get_clientdata(client); + + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + __fimc_md_set_camclk(fmd, si, false); + if (ret < 0) + goto mod_put; + + v4l2_set_subdev_hostdata(sd, si); + sd->grp_id = GRP_ID_SENSOR; + si->subdev = sd; + v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", + sd->name, fmd->num_sensors); + fmd->num_sensors++; + +mod_put: + module_put(client->driver->driver.owner); +dev_put: + device_unlock(&client->dev); + put_device(&client->dev); + return ret; +} + +/* Parse port node and register as a sub-device any sensor specified there. */ +static int fimc_md_parse_port_node(struct fimc_md *fmd, + struct device_node *port, + unsigned int index) +{ + struct device_node *rem, *ep, *np; + struct fimc_source_info *pd; + struct v4l2_of_endpoint endpoint; + int ret; + u32 val; + + pd = &fmd->sensor[index].pdata; + + /* Assume here a port node can have only one endpoint node. */ + ep = of_get_next_child(port, NULL); + if (!ep) + return 0; + + v4l2_of_parse_endpoint(ep, &endpoint); + if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS) + return -EINVAL; + + pd->mux_id = (endpoint.port - 1) & 0x1; + + rem = v4l2_of_get_remote_port_parent(ep); + of_node_put(ep); + if (rem == NULL) { + v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n", + ep->full_name); + return 0; + } + if (!of_property_read_u32(rem, "samsung,camclk-out", &val)) + pd->clk_id = val; + + if (!of_property_read_u32(rem, "clock-frequency", &val)) + pd->clk_frequency = val; + + if (pd->clk_frequency == 0) { + v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n", + rem->full_name); + of_node_put(rem); + return -EINVAL; + } + + if (fimc_input_is_parallel(endpoint.port)) { + if (endpoint.bus_type == V4L2_MBUS_PARALLEL) + pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601; + else + pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656; + pd->flags = endpoint.bus.parallel.flags; + } else if (fimc_input_is_mipi_csi(endpoint.port)) { + /* + * MIPI CSI-2: only input mux selection and + * the sensor's clock frequency is needed. + */ + pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; + } else { + v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n", + endpoint.port, rem->full_name); + } + /* + * For FIMC-IS handled sensors, that are placed under i2c-isp device + * node, FIMC is connected to the FIMC-IS through its ISP Writeback + * input. Sensors are attached to the FIMC-LITE hostdata interface + * directly or through MIPI-CSIS, depending on the external media bus + * used. This needs to be handled in a more reliable way, not by just + * checking parent's node name. + */ + np = of_get_parent(rem); + + if (np && !of_node_cmp(np->name, "i2c-isp")) + pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; + else + pd->fimc_bus_type = pd->sensor_bus_type; + + ret = fimc_md_of_add_sensor(fmd, rem, index); + of_node_put(rem); + + return ret; +} + +/* Register all SoC external sub-devices */ +static int fimc_md_of_sensors_register(struct fimc_md *fmd, + struct device_node *np) +{ + struct device_node *parent = fmd->pdev->dev.of_node; + struct device_node *node, *ports; + int index = 0; + int ret; + + /* Attach sensors linked to MIPI CSI-2 receivers */ + for_each_available_child_of_node(parent, node) { + struct device_node *port; + + if (of_node_cmp(node->name, "csis")) + continue; + /* The csis node can have only port subnode. */ + port = of_get_next_child(node, NULL); + if (!port) + continue; + + ret = fimc_md_parse_port_node(fmd, port, index); + if (ret < 0) + return ret; + index++; + } + + /* Attach sensors listed in the parallel-ports node */ + ports = of_get_child_by_name(parent, "parallel-ports"); + if (!ports) + return 0; + + for_each_child_of_node(ports, node) { + ret = fimc_md_parse_port_node(fmd, node, index); + if (ret < 0) + break; + index++; + } + + return 0; +} + static int __of_get_csis_id(struct device_node *np) { u32 reg = 0; @@ -281,14 +459,17 @@ static int __of_get_csis_id(struct device_node *np) return reg - FIMC_INPUT_MIPI_CSI2_0; } #else +#define fimc_md_of_sensors_register(fmd, np) (-ENOSYS) #define __of_get_csis_id(np) (-ENOSYS) #endif static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; + struct device_node *of_node = fmd->pdev->dev.of_node; struct fimc_dev *fd = NULL; - int num_clients, ret, i; + int num_clients = 0; + int ret, i; /* * Runtime resume one of the FIMC entities to make sure @@ -299,34 +480,41 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) fd = fmd->fimc[i]; if (!fd) return -ENXIO; + ret = pm_runtime_get_sync(&fd->pdev->dev); if (ret < 0) return ret; - WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor)); - num_clients = min_t(u32, pdata->num_clients, ARRAY_SIZE(fmd->sensor)); + if (of_node) { + fmd->num_sensors = 0; + ret = fimc_md_of_sensors_register(fmd, of_node); + } else if (pdata) { + WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor)); + num_clients = min_t(u32, pdata->num_clients, + ARRAY_SIZE(fmd->sensor)); + fmd->num_sensors = num_clients; - fmd->num_sensors = num_clients; - for (i = 0; i < num_clients; i++) { - struct v4l2_subdev *sd; + for (i = 0; i < num_clients; i++) { + struct v4l2_subdev *sd; - fmd->sensor[i].pdata = pdata->source_info[i]; - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); - if (ret) - break; - sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]); - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); - - if (!IS_ERR(sd)) { + fmd->sensor[i].pdata = pdata->source_info[i]; + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); + if (ret) + break; + sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]); + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); + + if (IS_ERR(sd)) { + fmd->sensor[i].subdev = NULL; + ret = PTR_ERR(sd); + break; + } fmd->sensor[i].subdev = sd; - } else { - fmd->sensor[i].subdev = NULL; - ret = PTR_ERR(sd); - break; + if (ret) + break; } - if (ret) - break; } + pm_runtime_put(&fd->pdev->dev); return ret; } @@ -1037,7 +1225,7 @@ static int fimc_md_probe(struct platform_device *pdev) if (ret) goto err_unlock; - if (dev->platform_data) { + if (dev->platform_data || dev->of_node) { ret = fimc_md_register_sensor_entities(fmd); if (ret) goto err_unlock; diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index e2c598962698..e2434bb0b308 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -45,6 +45,9 @@ enum fimc_bus_type { FIMC_BUS_TYPE_ISP_WRITEBACK = FIMC_BUS_TYPE_LCD_WRITEBACK_B, }; +#define fimc_input_is_parallel(x) ((x) == 1 || (x) == 2) +#define fimc_input_is_mipi_csi(x) ((x) == 3 || (x) == 4) + struct i2c_board_info; /** -- cgit v1.2.3 From fc39f46b54b600f053bf9bab757023344e97925e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Mar 2013 07:01:24 -0300 Subject: [media] V4L: Add MATRIX option to V4L2_CID_EXPOSURE_METERING control This patch adds a menu option to the V4L2_CID_EXPOSURE_METERING control for multi-zone metering. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 7 +++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 1 + include/uapi/linux/v4l2-controls.h | 1 + 3 files changed, 9 insertions(+) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index c8eb6c222274..8d7a77928d49 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3142,6 +3142,13 @@ giving priority to the center of the metered area. V4L2_EXPOSURE_METERING_SPOT  Measure only very small area at the center of the frame. + + V4L2_EXPOSURE_METERING_MATRIX  + A multi-zone metering. The light intensity is measured +in several points of the frame and the the results are combined. The +algorithm of the zones selection and their significance in calculating the +final value is device dependant. + diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index ec89fd16361c..ebb8e48619a2 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -234,6 +234,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Average", "Center Weighted", "Spot", + "Matrix", NULL }; static const char * const camera_auto_focus_range[] = { diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7da22cec30cd..69bd5bb0d5af 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -658,6 +658,7 @@ enum v4l2_exposure_metering { V4L2_EXPOSURE_METERING_AVERAGE = 0, V4L2_EXPOSURE_METERING_CENTER_WEIGHTED = 1, V4L2_EXPOSURE_METERING_SPOT = 2, + V4L2_EXPOSURE_METERING_MATRIX = 3, }; #define V4L2_CID_SCENE_MODE (V4L2_CID_CAMERA_CLASS_BASE+26) -- cgit v1.2.3 From 80f958f40d702ab322947f648bbd42174facf19d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 25 Feb 2013 13:20:21 -0300 Subject: [media] s5p-fimc: Remove dependency on fimc-core.h in fimc-lite driver Drop fimc-lite.h header inclusion to make the exynos-fimc-lite module independent on other modules. Move struct fimc_fmt declaration to the driver's private headers as it is used in multiple modules. Reported-by: Shaik Ameer Basha Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-core.h | 31 -------------------------- drivers/media/platform/s5p-fimc/fimc-lite.c | 1 - drivers/media/platform/s5p-fimc/fimc-lite.h | 3 +-- include/media/s5p_fimc.h | 34 +++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index 6355b3387b96..793333a33b24 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -136,37 +136,6 @@ enum fimc_color_fmt { /* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ #define FIMC_COLOR_RANGE_NARROW (1 << 3) -/** - * struct fimc_fmt - the driver's internal color format data - * @mbus_code: Media Bus pixel code, -1 if not applicable - * @name: format description - * @fourcc: the fourcc code for this format, 0 if not applicable - * @color: the corresponding fimc_color_fmt - * @memplanes: number of physically non-contiguous data planes - * @colplanes: number of physically contiguous data planes - * @depth: per plane driver's private 'number of bits per pixel' - * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no) - * @flags: flags indicating which operation mode format applies to - */ -struct fimc_fmt { - enum v4l2_mbus_pixelcode mbus_code; - char *name; - u32 fourcc; - u32 color; - u16 memplanes; - u16 colplanes; - u8 depth[VIDEO_MAX_PLANES]; - u16 mdataplanes; - u16 flags; -#define FMT_FLAGS_CAM (1 << 0) -#define FMT_FLAGS_M2M_IN (1 << 1) -#define FMT_FLAGS_M2M_OUT (1 << 2) -#define FMT_FLAGS_M2M (1 << 1 | 1 << 2) -#define FMT_HAS_ALPHA (1 << 3) -#define FMT_FLAGS_COMPRESSED (1 << 4) -#define FMT_FLAGS_WRITEBACK (1 << 5) -}; - /** * struct fimc_dma_offset - pixel offset information for DMA * @y_h: y value horizontal offset diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index 65082fe2578c..a37282e27cb0 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -32,7 +32,6 @@ #include #include "fimc-mdevice.h" -#include "fimc-core.h" #include "fimc-lite.h" #include "fimc-lite-reg.h" diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h index 7085761f8c4b..4c2345086366 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.h +++ b/drivers/media/platform/s5p-fimc/fimc-lite.h @@ -20,12 +20,11 @@ #include #include +#include #include #include #include -#include "fimc-core.h" - #define FIMC_LITE_DRV_NAME "exynos-fimc-lite" #define FLITE_CLK_NAME "flite" #define FIMC_LITE_MAX_DEVS 2 diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index e2434bb0b308..2363aff24df7 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -13,6 +13,7 @@ #define S5P_FIMC_H_ #include +#include /* * Enumeration of data inputs to the camera subsystem. @@ -93,6 +94,39 @@ struct s5p_platform_fimc { */ #define S5P_FIMC_TX_END_NOTIFY _IO('e', 0) +#define FIMC_MAX_PLANES 3 + +/** + * struct fimc_fmt - color format data structure + * @mbus_code: media bus pixel code, -1 if not applicable + * @name: format description + * @fourcc: fourcc code for this format, 0 if not applicable + * @color: the driver's private color format id + * @memplanes: number of physically non-contiguous data planes + * @colplanes: number of physically contiguous data planes + * @depth: per plane driver's private 'number of bits per pixel' + * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no) + * @flags: flags indicating which operation mode format applies to + */ +struct fimc_fmt { + enum v4l2_mbus_pixelcode mbus_code; + char *name; + u32 fourcc; + u32 color; + u16 memplanes; + u16 colplanes; + u8 depth[FIMC_MAX_PLANES]; + u16 mdataplanes; + u16 flags; +#define FMT_FLAGS_CAM (1 << 0) +#define FMT_FLAGS_M2M_IN (1 << 1) +#define FMT_FLAGS_M2M_OUT (1 << 2) +#define FMT_FLAGS_M2M (1 << 1 | 1 << 2) +#define FMT_HAS_ALPHA (1 << 3) +#define FMT_FLAGS_COMPRESSED (1 << 4) +#define FMT_FLAGS_WRITEBACK (1 << 5) +}; + enum fimc_subdev_index { IDX_SENSOR, IDX_CSIS, -- cgit v1.2.3 From 7b88fc086a217be7d16ec68a7f66093d344e39d7 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 18 Mar 2013 08:47:59 -0300 Subject: [media] soc_camera: Add RGB666 & RGB888 formats Based on work done by Katsuya Matsubara. Signed-off-by: Phil Edworthy Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/subdev-formats.xml | 206 ++++++++++++++++++++- Documentation/DocBook/media_api.tmpl | 1 + drivers/media/platform/soc_camera/soc_mediabus.c | 42 +++++ include/media/soc_camera.h | 7 +- include/media/soc_mediabus.h | 3 + include/uapi/linux/v4l2-mediabus.h | 6 +- 6 files changed, 253 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index cc51372ed5e0..adc61982df7b 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -93,19 +93,35 @@ RGB formats - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + Identifier @@ -117,6 +133,22 @@ Bit + 23 + 22 + 21 + 20 + 19 + 18 + 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 7 6 5 @@ -132,6 +164,7 @@ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE 0x1001 + &dash-ent-16; 0 0 0 @@ -145,6 +178,7 @@ + &dash-ent-16; g3 g2 g1 @@ -158,6 +192,7 @@ V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE 0x1002 + &dash-ent-16; g3 g2 g1 @@ -171,6 +206,7 @@ + &dash-ent-16; 0 0 0 @@ -184,6 +220,7 @@ V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE 0x1003 + &dash-ent-16; 0 r4 r3 @@ -197,6 +234,7 @@ + &dash-ent-16; g2 g1 g0 @@ -210,6 +248,7 @@ V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE 0x1004 + &dash-ent-16; g2 g1 g0 @@ -223,6 +262,7 @@ + &dash-ent-16; 0 r4 r3 @@ -236,6 +276,7 @@ V4L2_MBUS_FMT_BGR565_2X8_BE 0x1005 + &dash-ent-16; b4 b3 b2 @@ -249,6 +290,7 @@ + &dash-ent-16; g2 g1 g0 @@ -262,6 +304,7 @@ V4L2_MBUS_FMT_BGR565_2X8_LE 0x1006 + &dash-ent-16; g2 g1 g0 @@ -275,6 +318,7 @@ + &dash-ent-16; b4 b3 b2 @@ -288,6 +332,7 @@ V4L2_MBUS_FMT_RGB565_2X8_BE 0x1007 + &dash-ent-16; r4 r3 r2 @@ -301,6 +346,7 @@ + &dash-ent-16; g2 g1 g0 @@ -314,6 +360,7 @@ V4L2_MBUS_FMT_RGB565_2X8_LE 0x1008 + &dash-ent-16; g2 g1 g0 @@ -327,6 +374,27 @@ + &dash-ent-16; + r4 + r3 + r2 + r1 + r0 + g5 + g4 + g3 + + + V4L2_MBUS_FMT_RGB666_1X18 + 0x1009 + + - + - + - + - + - + - + r5 r4 r3 r2 @@ -335,6 +403,124 @@ g5 g4 g3 + g2 + g1 + g0 + b5 + b4 + b3 + b2 + b1 + b0 + + + V4L2_MBUS_FMT_RGB888_1X24 + 0x100a + + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + + + V4L2_MBUS_FMT_RGB888_2X12_BE + 0x100b + + &dash-ent-10; + - + - + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + g7 + g6 + g5 + g4 + + + + + + &dash-ent-10; + - + - + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + + + V4L2_MBUS_FMT_RGB888_2X12_LE + 0x100c + + &dash-ent-10; + - + - + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + + + + + + &dash-ent-10; + - + - + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + g7 + g6 + g5 + g4 diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl index 1f6593deb995..6a8b7158697f 100644 --- a/Documentation/DocBook/media_api.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -23,6 +23,7 @@ http://linuxtv.org/repo/"> ----------"> +----------------"> ]> diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c index 89dce097a827..7569e7746c92 100644 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ b/drivers/media/platform/soc_camera/soc_mediabus.c @@ -96,6 +96,42 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .order = SOC_MBUS_ORDER_LE, .layout = SOC_MBUS_LAYOUT_PACKED, }, +}, { + .code = V4L2_MBUS_FMT_RGB666_1X18, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB666/32bpp", + .bits_per_sample = 18, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_LE, + }, +}, { + .code = V4L2_MBUS_FMT_RGB888_1X24, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB888/32bpp", + .bits_per_sample = 24, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_LE, + }, +}, { + .code = V4L2_MBUS_FMT_RGB888_2X12_BE, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB888/32bpp", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_BE, + }, +}, { + .code = V4L2_MBUS_FMT_RGB888_2X12_LE, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB888/32bpp", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_LE, + }, }, { .code = V4L2_MBUS_FMT_SBGGR8_1X8, .fmt = { @@ -358,6 +394,10 @@ int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, *numerator = 1; *denominator = 1; return 0; + case SOC_MBUS_PACKING_EXTEND32: + *numerator = 1; + *denominator = 1; + return 0; case SOC_MBUS_PACKING_2X8_PADHI: case SOC_MBUS_PACKING_2X8_PADLO: *numerator = 2; @@ -392,6 +432,8 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) return width * 3 / 2; case SOC_MBUS_PACKING_VARIABLE: return 0; + case SOC_MBUS_PACKING_EXTEND32: + return width * 4; } return -EINVAL; } diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 2cc70cf318bf..ff77d08c30fd 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -292,12 +292,17 @@ struct soc_camera_sense { #define SOCAM_DATAWIDTH_8 SOCAM_DATAWIDTH(8) #define SOCAM_DATAWIDTH_9 SOCAM_DATAWIDTH(9) #define SOCAM_DATAWIDTH_10 SOCAM_DATAWIDTH(10) +#define SOCAM_DATAWIDTH_12 SOCAM_DATAWIDTH(12) #define SOCAM_DATAWIDTH_15 SOCAM_DATAWIDTH(15) #define SOCAM_DATAWIDTH_16 SOCAM_DATAWIDTH(16) +#define SOCAM_DATAWIDTH_18 SOCAM_DATAWIDTH(18) +#define SOCAM_DATAWIDTH_24 SOCAM_DATAWIDTH(24) #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \ SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \ - SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16) + SOCAM_DATAWIDTH_12 | SOCAM_DATAWIDTH_15 | \ + SOCAM_DATAWIDTH_16 | SOCAM_DATAWIDTH_18 | \ + SOCAM_DATAWIDTH_24) static inline void soc_camera_limit_side(int *start, int *length, unsigned int start_min, diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h index 0dc6f4625b92..d33f6d059692 100644 --- a/include/media/soc_mediabus.h +++ b/include/media/soc_mediabus.h @@ -26,6 +26,8 @@ * @SOC_MBUS_PACKING_VARIABLE: compressed formats with variable packing * @SOC_MBUS_PACKING_1_5X8: used for packed YUV 4:2:0 formats, where 4 * pixels occupy 6 bytes in RAM + * @SOC_MBUS_PACKING_EXTEND32: sample width (e.g., 24 bits) has to be extended + * to 32 bits */ enum soc_mbus_packing { SOC_MBUS_PACKING_NONE, @@ -34,6 +36,7 @@ enum soc_mbus_packing { SOC_MBUS_PACKING_EXTEND16, SOC_MBUS_PACKING_VARIABLE, SOC_MBUS_PACKING_1_5X8, + SOC_MBUS_PACKING_EXTEND32, }; /** diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h index b9b7bea04537..6ee63d09b32d 100644 --- a/include/uapi/linux/v4l2-mediabus.h +++ b/include/uapi/linux/v4l2-mediabus.h @@ -37,7 +37,7 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_FIXED = 0x0001, - /* RGB - next is 0x1009 */ + /* RGB - next is 0x100d */ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001, V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002, V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003, @@ -46,6 +46,10 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006, V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007, V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008, + V4L2_MBUS_FMT_RGB666_1X18 = 0x1009, + V4L2_MBUS_FMT_RGB888_1X24 = 0x100a, + V4L2_MBUS_FMT_RGB888_2X12_BE = 0x100b, + V4L2_MBUS_FMT_RGB888_2X12_LE = 0x100c, /* YUV (including grey) - next is 0x2017 */ V4L2_MBUS_FMT_Y8_1X8 = 0x2001, -- cgit v1.2.3 From c6e8d96d420307ab4efbb083c47452917fabd5dd Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 2 Apr 2013 11:41:19 -0300 Subject: [media] V4L: Remove incorrect EXPORT_SYMBOL() usage at v4l2-of.c v4l2_of_parse_parallel_bus() function is now static and EXPORT_SYMBOL() doesn't apply to it any more. Drop this meaningless statement, which was supposed to be done in the original merged patch. While at it, edit the copyright notice so it is sorted in both the v4l2-of.c and v4l2-of.h file in newest entries on top order, and state clearly I'm just the author of parts of the code, not the copyright owner. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-of.c | 3 +-- include/media/v4l2-of.h | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index e38e21064b5f..aa59639d013c 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -2,7 +2,7 @@ * V4L2 OF binding parsing library * * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki + * Author: Sylwester Nawrocki * * Copyright (C) 2012 Renesas Electronics Corp. * Author: Guennadi Liakhovetski @@ -103,7 +103,6 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, bus->flags = flags; } -EXPORT_SYMBOL(v4l2_of_parse_parallel_bus); /** * v4l2_of_parse_endpoint() - parse all endpoint node properties diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h index 00f91473498c..3a8a84124b44 100644 --- a/include/media/v4l2-of.h +++ b/include/media/v4l2-of.h @@ -1,12 +1,12 @@ /* * V4L2 OF binding parsing library * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Author: Sylwester Nawrocki + * * Copyright (C) 2012 Renesas Electronics Corp. * Author: Guennadi Liakhovetski * - * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. -- cgit v1.2.3 From e90ad659cde4d11ccbc935adcfe018799afcc22d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 20 Mar 2013 15:31:03 -0300 Subject: [media] exynos4-is: Allow colorspace conversion at FIMC-LITE The FIMC-LITE output DMA allows to configure different YUV order than the order at the camera input interface. Thus there is some limited colorspace conversion possible. This patch makes the color format variable be per FIMC-LITE input/output, rather than a global per device. This also fixes incorrect behavior where color format at the FIMC-LITE.N subdev's source pad is modified by VIDIOC_S_FMT ioctl on the related video node. YUV order definitions are corrected so that we use notation: | byte3 | byte2 | byte1 | byte0 -------+-------+-------+-------+------ YCBYCR | CR | Y | CB | Y YCRYCB | CB | Y | CR | Y CBYCRY | Y | CR | Y | CB CRYCBY | Y | CB | Y | CR Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite-reg.c | 4 +- drivers/media/platform/exynos4-is/fimc-lite-reg.h | 8 +-- drivers/media/platform/exynos4-is/fimc-lite.c | 76 +++++++++++++++-------- drivers/media/platform/exynos4-is/fimc-lite.h | 4 +- include/media/s5p_fimc.h | 2 + 5 files changed, 61 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index ac9663ce2a49..8cc0d39a2fea 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -127,7 +127,7 @@ static const u32 src_pixfmt_map[8][3] = { /* Set camera input pixel format and resolution */ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) { - enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code; + enum v4l2_mbus_pixelcode pixelcode = f->fmt->mbus_code; int i = ARRAY_SIZE(src_pixfmt_map); u32 cfg; @@ -227,7 +227,7 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) int i = ARRAY_SIZE(pixcode); while (--i >= 0) - if (pixcode[i][0] == dev->fmt->mbus_code) + if (pixcode[i][0] == f->fmt->mbus_code) break; cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT); diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h index 0e345844c13a..390383941c19 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h @@ -72,10 +72,10 @@ #define FLITE_REG_CIODMAFMT 0x18 #define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15) #define FLITE_REG_CIODMAFMT_PACK12 (1 << 14) -#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4) -#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4) -#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4) -#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4) +#define FLITE_REG_CIODMAFMT_YCBYCR (0 << 4) +#define FLITE_REG_CIODMAFMT_YCRYCB (1 << 4) +#define FLITE_REG_CIODMAFMT_CBYCRY (2 << 4) +#define FLITE_REG_CIODMAFMT_CRYCBY (3 << 4) #define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK (0x3 << 4) /* Camera Output Canvas */ diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index ba35328aaec5..b11e3583b9fa 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -46,6 +46,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_YCBYCR422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, @@ -53,6 +54,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_CBYCRY422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, @@ -60,6 +62,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_CRYCBY422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, @@ -67,6 +70,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_YCRYCB422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "RAW8 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG8, @@ -74,6 +78,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_RAW8, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .flags = FMT_FLAGS_RAW_BAYER, }, { .name = "RAW10 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG10, @@ -81,6 +86,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_RAW10, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .flags = FMT_FLAGS_RAW_BAYER, }, { .name = "RAW12 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG12, @@ -88,6 +94,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_RAW12, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, + .flags = FMT_FLAGS_RAW_BAYER, }, }; @@ -95,10 +102,11 @@ static const struct fimc_fmt fimc_lite_formats[] = { * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code * @pixelformat: fourcc to match, ignored if null * @mbus_code: media bus code to match, ignored if null + * @mask: the color format flags to match * @index: index to the fimc_lite_formats array, ignored if negative */ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat, - const u32 *mbus_code, int index) + const u32 *mbus_code, unsigned int mask, int index) { const struct fimc_fmt *fmt, *def_fmt = NULL; unsigned int i; @@ -109,6 +117,8 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat, for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) { fmt = &fimc_lite_formats[i]; + if (mask && !(fmt->flags & mask)) + continue; if (pixelformat && fmt->fourcc == *pixelformat) return fmt; if (mbus_code && fmt->mbus_code == *mbus_code) @@ -132,7 +142,7 @@ static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) if (sensor == NULL) return -ENXIO; - if (fimc->fmt == NULL) + if (fimc->inp_frame.fmt == NULL || fimc->out_frame.fmt == NULL) return -EINVAL; /* Get sensor configuration data from the sensor subdev */ @@ -339,13 +349,13 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, const struct v4l2_pix_format_mplane *pixm = NULL; struct fimc_lite *fimc = vq->drv_priv; struct flite_frame *frame = &fimc->out_frame; - const struct fimc_fmt *fmt = fimc->fmt; + const struct fimc_fmt *fmt = frame->fmt; unsigned long wh; int i; if (pfmt) { pixm = &pfmt->fmt.pix_mp; - fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1); + fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0, -1); wh = pixm->width * pixm->height; } else { wh = frame->f_width * frame->f_height; @@ -374,10 +384,10 @@ static int buffer_prepare(struct vb2_buffer *vb) struct fimc_lite *fimc = vq->drv_priv; int i; - if (fimc->fmt == NULL) + if (fimc->out_frame.fmt == NULL) return -EINVAL; - for (i = 0; i < fimc->fmt->memplanes; i++) { + for (i = 0; i < fimc->out_frame.fmt->memplanes; i++) { unsigned long size = fimc->payload[i]; if (vb2_plane_size(vb, i) < size) { @@ -530,15 +540,7 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, { struct flite_drvdata *dd = fimc->dd; const struct fimc_fmt *fmt; - - fmt = fimc_lite_find_format(fourcc, code, 0); - if (WARN_ON(!fmt)) - return NULL; - - if (code) - *code = fmt->mbus_code; - if (fourcc) - *fourcc = fmt->fourcc; + unsigned int flags = 0; if (pad == FLITE_SD_PAD_SINK) { v4l_bound_align_image(width, 8, dd->max_width, @@ -549,8 +551,18 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, ffs(dd->out_width_align) - 1, height, 0, fimc->inp_frame.rect.height, 0, 0); + flags = fimc->inp_frame.fmt->flags; } + fmt = fimc_lite_find_format(fourcc, code, flags, 0); + if (WARN_ON(!fmt)) + return NULL; + + if (code) + *code = fmt->mbus_code; + if (fourcc) + *fourcc = fmt->fourcc; + v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n", code ? *code : 0, *width, *height); @@ -629,7 +641,7 @@ static int fimc_lite_g_fmt_mplane(struct file *file, void *fh, struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0]; struct flite_frame *frame = &fimc->out_frame; - const struct fimc_fmt *fmt = fimc->fmt; + const struct fimc_fmt *fmt = frame->fmt; plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8; plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height; @@ -649,9 +661,22 @@ static int fimc_lite_try_fmt(struct fimc_lite *fimc, { u32 bpl = pixm->plane_fmt[0].bytesperline; struct flite_drvdata *dd = fimc->dd; + const struct fimc_fmt *inp_fmt = fimc->inp_frame.fmt; const struct fimc_fmt *fmt; - fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0); + if (WARN_ON(inp_fmt == NULL)) + return -EINVAL; + /* + * We allow some flexibility only for YUV formats. In case of raw + * raw Bayer the FIMC-LITE's output format must match its camera + * interface input format. + */ + if (inp_fmt->flags & FMT_FLAGS_YUV) + fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, + inp_fmt->flags, 0); + else + fmt = inp_fmt; + if (WARN_ON(fmt == NULL)) return -EINVAL; if (ffmt) @@ -697,7 +722,7 @@ static int fimc_lite_s_fmt_mplane(struct file *file, void *priv, if (ret < 0) return ret; - fimc->fmt = fmt; + frame->fmt = fmt; fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8, pixm->plane_fmt[0].sizeimage); frame->f_width = pixm->width; @@ -723,7 +748,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc) struct flite_frame *ff = &fimc->out_frame; sink_fmt.format.width = ff->f_width; sink_fmt.format.height = ff->f_height; - sink_fmt.format.code = fimc->fmt->mbus_code; + sink_fmt.format.code = fimc->inp_frame.fmt->mbus_code; } else { sink_fmt.pad = pad->index; sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; @@ -991,7 +1016,7 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, { const struct fimc_fmt *fmt; - fmt = fimc_lite_find_format(NULL, NULL, code->index); + fmt = fimc_lite_find_format(NULL, NULL, 0, code->index); if (!fmt) return -EINVAL; code->code = fmt->mbus_code; @@ -1004,7 +1029,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf = &fmt->format; - struct flite_frame *f = &fimc->out_frame; + struct flite_frame *f = &fimc->inp_frame; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { mf = v4l2_subdev_get_try_format(fh, fmt->pad); @@ -1014,7 +1039,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; mutex_lock(&fimc->lock); - mf->code = fimc->fmt->mbus_code; + mf->code = f->fmt->mbus_code; if (fmt->pad == FLITE_SD_PAD_SINK) { /* full camera input frame size */ @@ -1066,7 +1091,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, if (fmt->pad == FLITE_SD_PAD_SINK) { sink->f_width = mf->width; sink->f_height = mf->height; - fimc->fmt = ffmt; + sink->fmt = ffmt; /* Set sink crop rectangle */ sink->rect.width = mf->width; sink->rect.height = mf->height; @@ -1078,7 +1103,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, source->f_height = mf->height; } else { /* Allow changing format only on sink pad */ - mf->code = fimc->fmt->mbus_code; + mf->code = sink->fmt->mbus_code; mf->width = sink->rect.width; mf->height = sink->rect.height; } @@ -1219,7 +1244,8 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) memset(vfd, 0, sizeof(*vfd)); - fimc->fmt = &fimc_lite_formats[0]; + fimc->inp_frame.fmt = &fimc_lite_formats[0]; + fimc->out_frame.fmt = &fimc_lite_formats[0]; atomic_set(&fimc->out_path, FIMC_IO_DMA); snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 0b6380bb5c8a..8a8d26f58344 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -70,11 +70,13 @@ struct fimc_lite_events { * @f_width: full pixel width * @f_height: full pixel height * @rect: crop/composition rectangle + * @fmt: pointer to pixel format description data structure */ struct flite_frame { u16 f_width; u16 f_height; struct v4l2_rect rect; + const struct fimc_fmt *fmt; }; /** @@ -111,7 +113,6 @@ struct flite_buffer { * @clock: FIMC-LITE gate clock * @regs: memory mapped io registers * @irq_queue: interrupt handler waitqueue - * @fmt: pointer to color format description structure * @payload: image size in bytes (w x h x bpp) * @inp_frame: camera input frame structure * @out_frame: DMA output frame structure @@ -150,7 +151,6 @@ struct fimc_lite { void __iomem *regs; wait_queue_head_t irq_queue; - const struct fimc_fmt *fmt; unsigned long payload[FLITE_MAX_PLANES]; struct flite_frame inp_frame; struct flite_frame out_frame; diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 2363aff24df7..e316d15896f9 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -125,6 +125,8 @@ struct fimc_fmt { #define FMT_HAS_ALPHA (1 << 3) #define FMT_FLAGS_COMPRESSED (1 << 4) #define FMT_FLAGS_WRITEBACK (1 << 5) +#define FMT_FLAGS_RAW_BAYER (1 << 6) +#define FMT_FLAGS_YUV (1 << 7) }; enum fimc_subdev_index { -- cgit v1.2.3 From fde04ab95d43e55959f12b92711b0ca4fed40637 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 4 Apr 2013 13:25:30 -0300 Subject: [media] demux.h: Remove duplicated enum "enum dmx_ts_pes" and "typedef enum dmx_pes_type_t" are just the same enum declared twice, since Kernel (2.6.12). There's no reason to duplicate it there, and sparse complains about that: drivers/media/dvb-core/dmxdev.c:600:55: warning: mixing different enum types So, remove the internal define, keeping just the external one. Internally, use only "enum dmx_ts_pes", as it is too late to drop dmx_pes_type_t from the userspace API. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/demux.h | 39 ----------------------- drivers/media/dvb-core/dmxdev.c | 2 +- drivers/media/dvb-core/dvb_demux.c | 6 ++-- drivers/media/dvb-core/dvb_demux.h | 4 +-- drivers/media/dvb-core/dvb_net.c | 2 +- drivers/media/firewire/firedtv-dvb.c | 14 ++++---- drivers/media/pci/ttpci/av7110.c | 6 ++-- drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c | 10 +++--- drivers/media/usb/ttusb-dec/ttusb_dec.c | 20 ++++++------ include/uapi/linux/dvb/dmx.h | 2 +- 10 files changed, 33 insertions(+), 72 deletions(-) (limited to 'include') diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index eb91fd808c16..833191bcd810 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h @@ -83,45 +83,6 @@ enum dmx_success { #define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to the demux device, not to the dvr device */ -/* PES type for filters which write to built-in decoder */ -/* these should be kept identical to the types in dmx.h */ - -enum dmx_ts_pes -{ /* also send packets to decoder (if it exists) */ - DMX_TS_PES_AUDIO0, - DMX_TS_PES_VIDEO0, - DMX_TS_PES_TELETEXT0, - DMX_TS_PES_SUBTITLE0, - DMX_TS_PES_PCR0, - - DMX_TS_PES_AUDIO1, - DMX_TS_PES_VIDEO1, - DMX_TS_PES_TELETEXT1, - DMX_TS_PES_SUBTITLE1, - DMX_TS_PES_PCR1, - - DMX_TS_PES_AUDIO2, - DMX_TS_PES_VIDEO2, - DMX_TS_PES_TELETEXT2, - DMX_TS_PES_SUBTITLE2, - DMX_TS_PES_PCR2, - - DMX_TS_PES_AUDIO3, - DMX_TS_PES_VIDEO3, - DMX_TS_PES_TELETEXT3, - DMX_TS_PES_SUBTITLE3, - DMX_TS_PES_PCR3, - - DMX_TS_PES_OTHER -}; - -#define DMX_TS_PES_AUDIO DMX_TS_PES_AUDIO0 -#define DMX_TS_PES_VIDEO DMX_TS_PES_VIDEO0 -#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0 -#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0 -#define DMX_TS_PES_PCR DMX_TS_PES_PCR0 - - struct dmx_ts_feed { int is_filtering; /* Set to non-zero when filtering in progress */ struct dmx_demux *parent; /* Back-pointer */ diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 8896993e631f..a1a3a5159d71 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -569,7 +569,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, dmx_output_t otype; int ret; int ts_type; - dmx_pes_type_t ts_pes; + enum dmx_ts_pes ts_pes; struct dmx_ts_feed *tsfeed; feed->ts = NULL; diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 71641b2dde6b..3485655fa082 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -674,7 +674,7 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, return -ERESTARTSYS; if (ts_type & TS_DECODER) { - if (pes_type >= DMX_TS_PES_OTHER) { + if (pes_type >= DMX_PES_OTHER) { mutex_unlock(&demux->mutex); return -EINVAL; } @@ -846,7 +846,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, feed->pid = 0xffff; - if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) + if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_PES_OTHER) demux->pesfilter[feed->pes_type] = NULL; mutex_unlock(&demux->mutex); @@ -1268,7 +1268,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) INIT_LIST_HEAD(&dvbdemux->frontend_list); - for (i = 0; i < DMX_TS_PES_OTHER; i++) { + for (i = 0; i < DMX_PES_OTHER; i++) { dvbdemux->pesfilter[i] = NULL; dvbdemux->pids[i] = 0xffff; } diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index fa7188a253aa..ae7fc33c3231 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -119,8 +119,8 @@ struct dvb_demux { struct list_head frontend_list; - struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; - u16 pids[DMX_TS_PES_OTHER]; + struct dvb_demux_feed *pesfilter[DMX_PES_OTHER]; + u16 pids[DMX_PES_OTHER]; int playing; int recording; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 44225b186f6d..e17cb85d3ecf 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1044,7 +1044,7 @@ static int dvb_net_feed_start(struct net_device *dev) ret = priv->tsfeed->set(priv->tsfeed, priv->pid, /* pid */ TS_PACKET, /* type */ - DMX_TS_PES_OTHER, /* pes type */ + DMX_PES_OTHER, /* pes type */ 32768, /* circular buffer size */ timeout /* timeout */ ); diff --git a/drivers/media/firewire/firedtv-dvb.c b/drivers/media/firewire/firedtv-dvb.c index eb7496eab130..f710e17953e3 100644 --- a/drivers/media/firewire/firedtv-dvb.c +++ b/drivers/media/firewire/firedtv-dvb.c @@ -71,11 +71,11 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (dvbdmxfeed->type == DMX_TYPE_TS) { switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: + case DMX_PES_VIDEO: + case DMX_PES_AUDIO: + case DMX_PES_TELETEXT: + case DMX_PES_PCR: + case DMX_PES_OTHER: c = alloc_channel(fdtv); break; default: @@ -132,7 +132,7 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) (demux->dmx.frontend->source != DMX_MEMORY_FE))) { if (dvbdmxfeed->ts_type & TS_DECODER) { - if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || + if (dvbdmxfeed->pes_type >= DMX_PES_OTHER || !demux->pesfilter[dvbdmxfeed->pes_type]) return -EINVAL; @@ -141,7 +141,7 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) } if (!(dvbdmxfeed->ts_type & TS_DECODER && - dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) + dvbdmxfeed->pes_type < DMX_PES_OTHER)) return 0; } diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 3dc7aa9b6f40..f38329d29daa 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -990,7 +990,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (feed->type == DMX_TYPE_TS) { if ((feed->ts_type & TS_DECODER) && - (feed->pes_type <= DMX_TS_PES_PCR)) { + (feed->pes_type <= DMX_PES_PCR)) { switch (demux->dmx.frontend->source) { case DMX_MEMORY_FE: if (feed->ts_type & TS_DECODER) @@ -1051,14 +1051,14 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) if (feed->type == DMX_TYPE_TS) { if (feed->ts_type & TS_DECODER) { - if (feed->pes_type >= DMX_TS_PES_OTHER || + if (feed->pes_type >= DMX_PES_OTHER || !demux->pesfilter[feed->pes_type]) return -EINVAL; demux->pids[feed->pes_type] |= 0x8000; demux->pesfilter[feed->pes_type] = NULL; } if (feed->ts_type & TS_DECODER && - feed->pes_type < DMX_TS_PES_OTHER) { + feed->pes_type < DMX_PES_OTHER) { ret = dvb_feed_stop_pid(feed); } else if ((feed->ts_type & TS_PACKET) && diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c index e40718552850..21b9049c7b3f 100644 --- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c @@ -930,11 +930,11 @@ static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (dvbdmxfeed->type == DMX_TYPE_TS) { switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: + case DMX_PES_VIDEO: + case DMX_PES_AUDIO: + case DMX_PES_TELETEXT: + case DMX_PES_PCR: + case DMX_PES_OTHER: break; default: return -EINVAL; diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 504c81230339..e52c3b97f304 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -951,34 +951,34 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); + case DMX_PES_VIDEO: + dprintk(" pes_type: DMX_PES_VIDEO\n"); dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; dec->video_filter = dvbdmxfeed->filter; ttusb_dec_set_pids(dec); break; - case DMX_TS_PES_AUDIO: - dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); + case DMX_PES_AUDIO: + dprintk(" pes_type: DMX_PES_AUDIO\n"); dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; dec->audio_filter = dvbdmxfeed->filter; ttusb_dec_set_pids(dec); break; - case DMX_TS_PES_TELETEXT: + case DMX_PES_TELETEXT: dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; - dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); + dprintk(" pes_type: DMX_PES_TELETEXT(not supported)\n"); return -ENOSYS; - case DMX_TS_PES_PCR: - dprintk(" pes_type: DMX_TS_PES_PCR\n"); + case DMX_PES_PCR: + dprintk(" pes_type: DMX_PES_PCR\n"); dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; ttusb_dec_set_pids(dec); break; - case DMX_TS_PES_OTHER: - dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); + case DMX_PES_OTHER: + dprintk(" pes_type: DMX_PES_OTHER(not supported)\n"); return -ENOSYS; default: diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h index b2a9ad8cafdc..b4fb650d9d4f 100644 --- a/include/uapi/linux/dvb/dmx.h +++ b/include/uapi/linux/dvb/dmx.h @@ -51,7 +51,7 @@ typedef enum } dmx_input_t; -typedef enum +typedef enum dmx_ts_pes { DMX_PES_AUDIO0, DMX_PES_VIDEO0, -- cgit v1.2.3 From cdcd141c95f0c2b88e0b0869028c320cd031a23b Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 6 Apr 2013 14:21:36 -0300 Subject: [media] tuner-core: Change config from unsigned int to void * config looks like a hack that was added to tuner-core to allow some configuration of TDA8290 tuner (it's not used by any other driver). But with the new configuration options of tda8290 driver (no_i2c_gate and std_map), it's no longer sufficient. Change config to be void * instead, which allows passing tuner-dependent config struct to drivers. Also update saa7134 driver to reflect this change (no other driver uses this). Signed-off-by: Ondrej Zary Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-cards.c | 40 +++++++++++++++---------------- drivers/media/pci/saa7134/saa7134.h | 3 ++- drivers/media/v4l2-core/tuner-core.c | 20 ++++++---------- include/media/tuner.h | 2 +- 4 files changed, 30 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index dc68cf1070f7..29fb7a9ac2a4 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -2760,7 +2760,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3291,7 +3291,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 1, + .tda829x_conf = { .lna_cfg = 1 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x000200000, .inputs = {{ @@ -3395,7 +3395,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 1, + .tda829x_conf = { .lna_cfg = 1 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200100, .inputs = {{ @@ -3426,7 +3426,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 3, + .tda829x_conf = { .lna_cfg = 3 }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_SERIAL, .ts_force_val = 1, @@ -3459,7 +3459,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 3, + .tda829x_conf = { .lna_cfg = 3 }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_SERIAL, .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ @@ -3683,7 +3683,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3736,7 +3736,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3754,7 +3754,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -3887,7 +3887,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, /* FIXME: analog tv untested */ @@ -3903,7 +3903,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 0x020200000, .inputs = {{ .name = name_tv, @@ -3937,7 +3937,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .gpiomask = 0x020200000, .inputs = {{ .name = name_tv, @@ -4737,7 +4737,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -4823,7 +4823,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, @@ -4847,7 +4847,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = { { @@ -5057,7 +5057,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -5087,7 +5087,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -5176,7 +5176,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = { { @@ -5406,7 +5406,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_PARALLEL, .inputs = {{ @@ -5629,7 +5629,7 @@ struct saa7134_board saa7134_boards[] = { .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, - .tuner_config = 3, + .tda829x_conf = { .lna_cfg = 3 }, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .gpiomask = 0x02050000, @@ -7633,7 +7633,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) { tun_setup.type = dev->tuner_type; tun_setup.addr = dev->tuner_addr; - tun_setup.config = saa7134_boards[dev->board].tuner_config; + tun_setup.config = &saa7134_boards[dev->board].tda829x_conf; tun_setup.tuner_callback = saa7134_tuner_callback; tun_setup.mode_mask = mode_mask; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 62169dd74c6a..b90b48821104 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -45,6 +45,7 @@ #if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB) #include #endif +#include "tda8290.h" #define UNSET (-1U) @@ -390,7 +391,7 @@ struct saa7134_board { unsigned char rds_addr; unsigned int tda9887_conf; - unsigned int tuner_config; + struct tda829x_config tda829x_conf; /* peripheral I/O */ enum saa7134_video_out video_out; diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index cf9a9af90322..7d60c5d38ca0 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -132,7 +132,7 @@ struct tuner { bool standby; /* Standby mode */ unsigned int type; /* chip type id */ - unsigned int config; + void *config; const char *name; }; @@ -270,9 +270,8 @@ static const struct analog_demod_ops tuner_analog_ops = { * @c: i2c_client descriptoy * @type: type of the tuner (e. g. tuner number) * @new_mode_mask: Indicates if tuner supports TV and/or Radio - * @new_config: an optional parameter ranging from 0-255 used by - a few tuners to adjust an internal parameter, - like LNA mode + * @new_config: an optional parameter used by a few tuners to adjust + internal parameters, like LNA mode * @tuner_callback: an optional function to be called when switching * to analog mode * @@ -280,7 +279,7 @@ static const struct analog_demod_ops tuner_analog_ops = { * by tun_setup structure. It contains several per-tuner initialization "magic" */ static void set_type(struct i2c_client *c, unsigned int type, - unsigned int new_mode_mask, unsigned int new_config, + unsigned int new_mode_mask, void *new_config, int (*tuner_callback) (void *dev, int component, int cmd, int arg)) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); @@ -295,8 +294,7 @@ static void set_type(struct i2c_client *c, unsigned int type, } t->type = type; - /* prevent invalid config values */ - t->config = new_config < 256 ? new_config : 0; + t->config = new_config; if (tuner_callback != NULL) { tuner_dbg("defining GPIO callback\n"); t->fe.callback = tuner_callback; @@ -314,11 +312,8 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_PHILIPS_TDA8290: { - struct tda829x_config cfg = { - .lna_cfg = t->config, - }; if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter, - t->i2c->addr, &cfg)) + t->i2c->addr, t->config)) goto attach_failed; break; } @@ -407,7 +402,6 @@ static void set_type(struct i2c_client *c, unsigned int type, case TUNER_NXP_TDA18271: { struct tda18271_config cfg = { - .config = t->config, .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, }; @@ -509,7 +503,7 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner *t = to_tuner(sd); struct i2c_client *c = v4l2_get_subdevdata(sd); - tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", + tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=%p\n", tun_setup->type, tun_setup->addr, tun_setup->mode_mask, diff --git a/include/media/tuner.h b/include/media/tuner.h index 24eaafe461bd..b46ebb48fe74 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -192,7 +192,7 @@ struct tuner_setup { unsigned short addr; /* I2C address */ unsigned int type; /* Tuner type */ unsigned int mode_mask; /* Allowed tuner modes */ - unsigned int config; /* configuraion for more complex tuners */ + void *config; /* configuraion for more complex tuners */ int (*tuner_callback) (void *dev, int component, int cmd, int arg); }; -- cgit v1.2.3 From 488f29d00e819b178f9060fa08028b73d5f8d916 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 9 Apr 2013 07:19:27 -0300 Subject: [media] exynos4-is: Move the subdev group ID definitions to public header Move the sub-device group ID definitions to the driver's public header so they are available to other media drivers that need to share modules found in exynos4-is. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.h | 9 --------- include/media/s5p_fimc.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 0b14cd575747..7f126c3adacf 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -30,15 +30,6 @@ #define PINCTRL_STATE_IDLE "idle" -/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ -#define GRP_ID_SENSOR (1 << 8) -#define GRP_ID_FIMC_IS_SENSOR (1 << 9) -#define GRP_ID_WRITEBACK (1 << 10) -#define GRP_ID_CSIS (1 << 11) -#define GRP_ID_FIMC (1 << 12) -#define GRP_ID_FLITE (1 << 13) -#define GRP_ID_FIMC_IS (1 << 14) - #define FIMC_MAX_SENSORS 8 #define FIMC_MAX_CAMCLKS 2 diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index e316d15896f9..f50969025ef3 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -49,6 +49,17 @@ enum fimc_bus_type { #define fimc_input_is_parallel(x) ((x) == 1 || (x) == 2) #define fimc_input_is_mipi_csi(x) ((x) == 3 || (x) == 4) +/* + * The subdevices' group IDs. + */ +#define GRP_ID_SENSOR (1 << 8) +#define GRP_ID_FIMC_IS_SENSOR (1 << 9) +#define GRP_ID_WRITEBACK (1 << 10) +#define GRP_ID_CSIS (1 << 11) +#define GRP_ID_FIMC (1 << 12) +#define GRP_ID_FLITE (1 << 13) +#define GRP_ID_FIMC_IS (1 << 14) + struct i2c_board_info; /** -- cgit v1.2.3 From d67492585d8308a22a841956f1e629ef3b7d0315 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 21 Dec 2012 16:11:55 -0300 Subject: [media] mt9p031: Use the common clock framework Configure the device external clock using the common clock framework instead of a board code callback function. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 21 ++++++++++++++------- include/media/mt9p031.h | 2 -- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index ecf4492c6b8e..28cf95b37285 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -122,6 +123,7 @@ struct mt9p031 { struct mutex power_lock; /* lock to protect power_count */ int power_count; + struct clk *clk; struct regulator *vaa; struct regulator *vdd; struct regulator *vdd_io; @@ -200,7 +202,7 @@ static int mt9p031_reset(struct mt9p031 *mt9p031) 0); } -static int mt9p031_pll_setup(struct mt9p031 *mt9p031) +static int mt9p031_clk_setup(struct mt9p031 *mt9p031) { static const struct aptina_pll_limits limits = { .ext_clock_min = 6000000, @@ -221,6 +223,12 @@ static int mt9p031_pll_setup(struct mt9p031 *mt9p031) struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); struct mt9p031_platform_data *pdata = mt9p031->pdata; + mt9p031->clk = devm_clk_get(&client->dev, NULL); + if (IS_ERR(mt9p031->clk)) + return PTR_ERR(mt9p031->clk); + + clk_set_rate(mt9p031->clk, pdata->ext_freq); + mt9p031->pll.ext_clock = pdata->ext_freq; mt9p031->pll.pix_clock = pdata->target_freq; @@ -275,9 +283,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) regulator_enable(mt9p031->vaa); /* Emable clock */ - if (mt9p031->pdata->set_xclk) - mt9p031->pdata->set_xclk(&mt9p031->subdev, - mt9p031->pdata->ext_freq); + if (mt9p031->clk) + clk_prepare_enable(mt9p031->clk); /* Now RESET_BAR must be high */ if (mt9p031->reset != -1) { @@ -299,8 +306,8 @@ static void mt9p031_power_off(struct mt9p031 *mt9p031) regulator_disable(mt9p031->vdd_io); regulator_disable(mt9p031->vdd); - if (mt9p031->pdata->set_xclk) - mt9p031->pdata->set_xclk(&mt9p031->subdev, 0); + if (mt9p031->clk) + clk_disable_unprepare(mt9p031->clk); } static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on) @@ -1033,7 +1040,7 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->reset = pdata->reset; } - ret = mt9p031_pll_setup(mt9p031); + ret = mt9p031_clk_setup(mt9p031); done: if (ret < 0) { diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h index 0c97b19af293..b1e63f2b72bd 100644 --- a/include/media/mt9p031.h +++ b/include/media/mt9p031.h @@ -5,13 +5,11 @@ struct v4l2_subdev; /* * struct mt9p031_platform_data - MT9P031 platform data - * @set_xclk: Clock frequency set callback * @reset: Chip reset GPIO (set to -1 if not used) * @ext_freq: Input clock frequency * @target_freq: Pixel clock frequency */ struct mt9p031_platform_data { - int (*set_xclk)(struct v4l2_subdev *subdev, int hz); int reset; int ext_freq; int target_freq; -- cgit v1.2.3 From cd634f1bfc182e564f33809fdca33027bb99fceb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 27 Mar 2013 08:04:23 -0300 Subject: [media] v4l2: put VIDIOC_DBG_G_CHIP_NAME under ADV_DEBUG Only enable this ioctl if the VIDEO_ADV_DEBUG config option is set. This prevents abuse from both userspace and kernelspace (some bridge drivers abuse DBG_G_CHIP_IDENT, lets prevent that from happening again with this ioctl). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml | 3 +++ drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/v4l2-core/v4l2-dev.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 8 ++++---- include/media/v4l2-ioctl.h | 6 +++--- 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml index 4921346fabd7..5fce8d84288e 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml @@ -63,6 +63,9 @@ card. Regular applications must not use it. When you found a chip specific bug, please contact the linux-media mailing list (&v4l-ml;) so it can be fixed. + Additionally the Linux kernel must be compiled with the +CONFIG_VIDEO_ADV_DEBUG option to enable this ioctl. + To query the driver applications must initialize the match.type and match.addr or match.name diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 792ead1025d7..39951f5731e1 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1331,6 +1331,7 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, return 0; } +#ifdef CONFIG_VIDEO_ADV_DEBUG static int vidioc_g_chip_name(struct file *file, void *priv, struct v4l2_dbg_chip_name *chip) { @@ -1346,7 +1347,6 @@ static int vidioc_g_chip_name(struct file *file, void *priv, return 0; } -#ifdef CONFIG_VIDEO_ADV_DEBUG static int em28xx_reg_len(int reg) { switch (reg) { @@ -1796,8 +1796,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, - .vidioc_g_chip_name = vidioc_g_chip_name, #ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_chip_name = vidioc_g_chip_name, .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 670b9ca8ecbe..1c3b43cf773d 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -591,8 +591,8 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); - set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); #ifdef CONFIG_VIDEO_ADV_DEBUG + set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); #endif diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 336ed2dd607c..feac07e50293 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1873,6 +1873,7 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { +#ifdef CONFIG_VIDEO_ADV_DEBUG struct video_device *vfd = video_devdata(file); struct v4l2_dbg_chip_name *p = arg; struct v4l2_subdev *sd; @@ -1880,12 +1881,10 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, switch (p->match.type) { case V4L2_CHIP_MATCH_BRIDGE: -#ifdef CONFIG_VIDEO_ADV_DEBUG if (ops->vidioc_s_register) p->flags |= V4L2_CHIP_FL_WRITABLE; if (ops->vidioc_g_register) p->flags |= V4L2_CHIP_FL_READABLE; -#endif if (ops->vidioc_g_chip_name) return ops->vidioc_g_chip_name(file, fh, arg); if (p->match.addr) @@ -1904,12 +1903,10 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, break; v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { if (v4l_dbg_found_match(&p->match, sd, idx++)) { -#ifdef CONFIG_VIDEO_ADV_DEBUG if (sd->ops->core && sd->ops->core->s_register) p->flags |= V4L2_CHIP_FL_WRITABLE; if (sd->ops->core && sd->ops->core->g_register) p->flags |= V4L2_CHIP_FL_READABLE; -#endif strlcpy(p->name, sd->name, sizeof(p->name)); return 0; } @@ -1917,6 +1914,9 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, break; } return -EINVAL; +#else + return -ENOTTY; +#endif } static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index b273f0e81818..6b917d69e408 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -243,12 +243,12 @@ struct v4l2_ioctl_ops { struct v4l2_dbg_register *reg); int (*vidioc_s_register) (struct file *file, void *fh, const struct v4l2_dbg_register *reg); -#endif - int (*vidioc_g_chip_ident) (struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip); int (*vidioc_g_chip_name) (struct file *file, void *fh, struct v4l2_dbg_chip_name *chip); +#endif + int (*vidioc_g_chip_ident) (struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip); int (*vidioc_enum_framesizes) (struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); -- cgit v1.2.3 From 3eef25107cab65a1158b11ba373fb9b4fc25b4b8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Apr 2013 04:08:19 -0300 Subject: [media] v4l2: drop V4L2_CHIP_MATCH_SUBDEV_NAME After using the new VIDIOC_DBG_G_CHIP_NAME ioctl I realized that the matching by name possibility is useless. Just drop it and rename MATCH_SUBDEV_IDX to just MATCH_SUBDEV. The v4l2-dbg utility is much better placed to match by name by just enumerating all bridge and subdev devices until chip_name.name matches. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml | 7 +-- .../DocBook/media/v4l/vidioc-dbg-g-chip-name.xml | 18 +------ .../DocBook/media/v4l/vidioc-dbg-g-register.xml | 17 +------ drivers/media/v4l2-core/v4l2-common.c | 3 +- drivers/media/v4l2-core/v4l2-ioctl.c | 55 ++++++++-------------- include/uapi/linux/videodev2.h | 3 +- 6 files changed, 26 insertions(+), 77 deletions(-) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml index 82e43c6c72b8..921e18550d26 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml @@ -221,13 +221,8 @@ the values from . Match the nth anciliary AC97 chip. - V4L2_CHIP_MATCH_SUBDEV_NAME + V4L2_CHIP_MATCH_SUBDEV 4 - Match the sub-device by name. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_SUBDEV_IDX - 5 Match the nth sub-device. Can't be used with this ioctl. diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml index 5fce8d84288e..fa3bd42ab167 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml @@ -87,16 +87,7 @@ connected to the PCI or USB bus. Non-zero numbers identify specific parts of the bridge chip such as an AC97 register block. When match.type is -V4L2_CHIP_MATCH_SUBDEV_NAME, -match.name contains the name of a sub-device. -For instance -"saa7127 6-0044" will match the saa7127 sub-device -at the given i2c bus. This match type is not very useful for this ioctl -and is here only for consistency. - - - When match.type is -V4L2_CHIP_MATCH_SUBDEV_IDX, +V4L2_CHIP_MATCH_SUBDEV, match.addr selects the nth sub-device. This allows you to enumerate over all sub-devices. @@ -207,13 +198,8 @@ is set, then the driver supports reading registers from the device. If Match the nth anciliary AC97 chip. Can't be used with this ioctl. - V4L2_CHIP_MATCH_SUBDEV_NAME + V4L2_CHIP_MATCH_SUBDEV 4 - Match the sub-device by name. - - - V4L2_CHIP_MATCH_SUBDEV_IDX - 5 Match the nth sub-device. diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml index 3082b4149dbe..db7844f2439f 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml @@ -123,15 +123,7 @@ bus address. on the TV card. When match.type is -V4L2_CHIP_MATCH_SUBDEV_NAME, -match.name contains the sub-device name. -For instance -"saa7127 6-0044" will match this specific saa7127 -sub-device. Again with the &VIDIOC-DBG-G-CHIP-NAME; ioctl you can find -out which sub-devices are present. - - When match.type is -V4L2_CHIP_MATCH_SUBDEV_IDX, +V4L2_CHIP_MATCH_SUBDEV, match.addr selects the nth sub-device. @@ -250,13 +242,8 @@ register. Match the nth anciliary AC97 chip. - V4L2_CHIP_MATCH_SUBDEV_NAME + V4L2_CHIP_MATCH_SUBDEV 4 - Match the sub-device by name. - - - V4L2_CHIP_MATCH_SUBDEV_IDX - 5 Match the nth sub-device. diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index f8fac9cefc3c..3fed63f4e026 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -254,8 +254,7 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match return len && !strncmp(c->driver->driver.name, match->name, len); case V4L2_CHIP_MATCH_I2C_ADDR: return c->addr == match->addr; - case V4L2_CHIP_MATCH_SUBDEV_IDX: - case V4L2_CHIP_MATCH_SUBDEV_NAME: + case V4L2_CHIP_MATCH_SUBDEV: return 1; default: return 0; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index feac07e50293..7a96162f544f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -629,8 +629,7 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) const struct v4l2_dbg_chip_ident *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -644,8 +643,7 @@ static void v4l_print_dbg_chip_name(const void *arg, bool write_only) const struct v4l2_dbg_chip_name *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -658,8 +656,7 @@ static void v4l_print_dbg_register(const void *arg, bool write_only) const struct v4l2_dbg_register *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -1791,14 +1788,6 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, return ret; } -static bool v4l_dbg_found_match(const struct v4l2_dbg_match *match, - struct v4l2_subdev *sd, int idx) -{ - if (match->type == V4L2_CHIP_MATCH_SUBDEV_IDX) - return match->addr == idx; - return !strcmp(match->name, sd->name); -} - static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1810,14 +1799,12 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) { if (vfd->v4l2_dev == NULL) return -EINVAL; - v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { - if (v4l_dbg_found_match(&p->match, sd, idx++)) + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) + if (p->match.addr == idx++) return v4l2_subdev_call(sd, core, g_register, p); - } return -EINVAL; } if (ops->vidioc_g_register) @@ -1839,14 +1826,12 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) { if (vfd->v4l2_dev == NULL) return -EINVAL; - v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { - if (v4l_dbg_found_match(&p->match, sd, idx++)) + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) + if (p->match.addr == idx++) return v4l2_subdev_call(sd, core, s_register, p); - } return -EINVAL; } if (ops->vidioc_s_register) @@ -1864,8 +1849,7 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, p->ident = V4L2_IDENT_NONE; p->revision = 0; - if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX) + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) return -EINVAL; return ops->vidioc_g_chip_ident(file, fh, p); } @@ -1897,19 +1881,18 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, strlcpy(p->name, "bridge", sizeof(p->name)); return 0; - case V4L2_CHIP_MATCH_SUBDEV_IDX: - case V4L2_CHIP_MATCH_SUBDEV_NAME: + case V4L2_CHIP_MATCH_SUBDEV: if (vfd->v4l2_dev == NULL) break; v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { - if (v4l_dbg_found_match(&p->match, sd, idx++)) { - if (sd->ops->core && sd->ops->core->s_register) - p->flags |= V4L2_CHIP_FL_WRITABLE; - if (sd->ops->core && sd->ops->core->g_register) - p->flags |= V4L2_CHIP_FL_READABLE; - strlcpy(p->name, sd->name, sizeof(p->name)); - return 0; - } + if (p->match.addr != idx++) + continue; + if (sd->ops->core && sd->ops->core->s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (sd->ops->core && sd->ops->core->g_register) + p->flags |= V4L2_CHIP_FL_READABLE; + strlcpy(p->name, sd->name, sizeof(p->name)); + return 0; } break; } diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index e9c49c5e6416..4c941c103c44 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1812,8 +1812,7 @@ struct v4l2_event_subscription { #define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ #define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ #define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ -#define V4L2_CHIP_MATCH_SUBDEV_NAME 4 /* Match against subdev name */ -#define V4L2_CHIP_MATCH_SUBDEV_IDX 5 /* Match against subdev index */ +#define V4L2_CHIP_MATCH_SUBDEV 4 /* Match against subdev index */ struct v4l2_dbg_match { __u32 type; /* Match type */ -- cgit v1.2.3 From 96b03d2a3078d5e95a8b106634faa7cea88ebe5e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 6 Apr 2013 06:16:58 -0300 Subject: [media] v4l2: rename VIDIOC_DBG_G_CHIP_NAME to _CHIP_INFO This ioctl will be extended to return more information than just the name. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/compat.xml | 2 +- Documentation/DocBook/media/v4l/v4l2.xml | 4 +- .../DocBook/media/v4l/vidioc-dbg-g-chip-info.xml | 223 +++++++++++++++++++++ .../DocBook/media/v4l/vidioc-dbg-g-chip-name.xml | 223 --------------------- .../DocBook/media/v4l/vidioc-dbg-g-register.xml | 10 +- drivers/media/usb/em28xx/em28xx-video.c | 8 +- drivers/media/v4l2-core/v4l2-dev.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 14 +- include/media/v4l2-ioctl.h | 4 +- include/uapi/linux/videodev2.h | 8 +- 10 files changed, 249 insertions(+), 249 deletions(-) create mode 100644 Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml delete mode 100644 Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index e44161ffdd07..f43542ae2981 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2507,7 +2507,7 @@ that used it. It was originally scheduled for removal in 2.6.35. - Added new debugging ioctl &VIDIOC-DBG-G-CHIP-NAME;. + Added new debugging ioctl &VIDIOC-DBG-G-CHIP-INFO;. diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index c1f334084213..bfc93cdcf696 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -147,7 +147,7 @@ applications. --> Remove obsolete and unused DV_PRESET ioctls: VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_QUERY_DV_PRESET and VIDIOC_ENUM_DV_PRESET. Remove the related v4l2_input/output capability - flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. Added VIDIOC_DBG_G_CHIP_NAME. + flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. Added VIDIOC_DBG_G_CHIP_INFO. @@ -548,7 +548,7 @@ and discussions on the V4L mailing list. &sub-create-bufs; &sub-cropcap; &sub-dbg-g-chip-ident; - &sub-dbg-g-chip-name; + &sub-dbg-g-chip-info; &sub-dbg-g-register; &sub-decoder-cmd; &sub-dqevent; diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml new file mode 100644 index 000000000000..e1cece6c5de1 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml @@ -0,0 +1,223 @@ + + + ioctl VIDIOC_DBG_G_CHIP_INFO + &manvol; + + + + VIDIOC_DBG_G_CHIP_INFO + Identify the chips on a TV card + + + + + + int ioctl + int fd + int request + struct v4l2_dbg_chip_info +*argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_DBG_G_CHIP_INFO + + + + argp + + + + + + + + + Description + + + Experimental + + This is an experimental interface and may change in +the future. + + + For driver debugging purposes this ioctl allows test +applications to query the driver about the chips present on the TV +card. Regular applications must not use it. When you found a chip +specific bug, please contact the linux-media mailing list (&v4l-ml;) +so it can be fixed. + + Additionally the Linux kernel must be compiled with the +CONFIG_VIDEO_ADV_DEBUG option to enable this ioctl. + + To query the driver applications must initialize the +match.type and +match.addr or match.name +fields of a &v4l2-dbg-chip-info; +and call VIDIOC_DBG_G_CHIP_INFO with a pointer to +this structure. On success the driver stores information about the +selected chip in the name and +flags fields. On failure the structure +remains unchanged. + + When match.type is +V4L2_CHIP_MATCH_BRIDGE, +match.addr selects the nth bridge 'chip' +on the TV card. You can enumerate all chips by starting at zero and +incrementing match.addr by one until +VIDIOC_DBG_G_CHIP_INFO fails with an &EINVAL;. +The number zero always selects the bridge chip itself, ⪚ the chip +connected to the PCI or USB bus. Non-zero numbers identify specific +parts of the bridge chip such as an AC97 register block. + + When match.type is +V4L2_CHIP_MATCH_SUBDEV, +match.addr selects the nth sub-device. This +allows you to enumerate over all sub-devices. + + On success, the name field will +contain a chip name and the flags field will +contain V4L2_CHIP_FL_READABLE if the driver supports +reading registers from the device or V4L2_CHIP_FL_WRITABLE +if the driver supports writing registers to the device. + + We recommended the v4l2-dbg +utility over calling this ioctl directly. It is available from the +LinuxTV v4l-dvb repository; see http://linuxtv.org/repo/ for +access instructions. + + +
+ struct <structname>v4l2_dbg_match</structname> + + &cs-ustr; + + + __u32 + type + See for a list of +possible types. + + + union + (anonymous) + + + + __u32 + addr + Match a chip by this number, interpreted according +to the type field. + + + + char + name[32] + Match a chip by this name, interpreted according +to the type field. + + + +
+ + + struct <structname>v4l2_dbg_chip_info</structname> + + &cs-str; + + + struct v4l2_dbg_match + match + How to match the chip, see . + + + char + name[32] + The name of the chip. + + + __u32 + flags + Set by the driver. If V4L2_CHIP_FL_READABLE +is set, then the driver supports reading registers from the device. If +V4L2_CHIP_FL_WRITABLE is set, then it supports writing registers. + + + __u32 + reserved[8] + Reserved fields, both application and driver must set these to 0. + + + +
+ + + + Chip Match Types + + &cs-def; + + + V4L2_CHIP_MATCH_BRIDGE + 0 + Match the nth chip on the card, zero for the + bridge chip. Does not match sub-devices. + + + V4L2_CHIP_MATCH_I2C_DRIVER + 1 + Match an &i2c; chip by its driver name. Can't be used with this ioctl. + + + V4L2_CHIP_MATCH_I2C_ADDR + 2 + Match a chip by its 7 bit &i2c; bus address. Can't be used with this ioctl. + + + V4L2_CHIP_MATCH_AC97 + 3 + Match the nth anciliary AC97 chip. Can't be used with this ioctl. + + + V4L2_CHIP_MATCH_SUBDEV + 4 + Match the nth sub-device. + + + +
+ + + + &return-value; + + + + EINVAL + + The match_type is invalid or +no device could be matched. + + + + + diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml deleted file mode 100644 index fa3bd42ab167..000000000000 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml +++ /dev/null @@ -1,223 +0,0 @@ - - - ioctl VIDIOC_DBG_G_CHIP_NAME - &manvol; - - - - VIDIOC_DBG_G_CHIP_NAME - Identify the chips on a TV card - - - - - - int ioctl - int fd - int request - struct v4l2_dbg_chip_name -*argp - - - - - - Arguments - - - - fd - - &fd; - - - - request - - VIDIOC_DBG_G_CHIP_NAME - - - - argp - - - - - - - - - Description - - - Experimental - - This is an experimental interface and may change in -the future. - - - For driver debugging purposes this ioctl allows test -applications to query the driver about the chips present on the TV -card. Regular applications must not use it. When you found a chip -specific bug, please contact the linux-media mailing list (&v4l-ml;) -so it can be fixed. - - Additionally the Linux kernel must be compiled with the -CONFIG_VIDEO_ADV_DEBUG option to enable this ioctl. - - To query the driver applications must initialize the -match.type and -match.addr or match.name -fields of a &v4l2-dbg-chip-name; -and call VIDIOC_DBG_G_CHIP_NAME with a pointer to -this structure. On success the driver stores information about the -selected chip in the name and -flags fields. On failure the structure -remains unchanged. - - When match.type is -V4L2_CHIP_MATCH_BRIDGE, -match.addr selects the nth bridge 'chip' -on the TV card. You can enumerate all chips by starting at zero and -incrementing match.addr by one until -VIDIOC_DBG_G_CHIP_NAME fails with an &EINVAL;. -The number zero always selects the bridge chip itself, ⪚ the chip -connected to the PCI or USB bus. Non-zero numbers identify specific -parts of the bridge chip such as an AC97 register block. - - When match.type is -V4L2_CHIP_MATCH_SUBDEV, -match.addr selects the nth sub-device. This -allows you to enumerate over all sub-devices. - - On success, the name field will -contain a chip name and the flags field will -contain V4L2_CHIP_FL_READABLE if the driver supports -reading registers from the device or V4L2_CHIP_FL_WRITABLE -if the driver supports writing registers to the device. - - We recommended the v4l2-dbg -utility over calling this ioctl directly. It is available from the -LinuxTV v4l-dvb repository; see http://linuxtv.org/repo/ for -access instructions. - - - - struct <structname>v4l2_dbg_match</structname> - - &cs-ustr; - - - __u32 - type - See for a list of -possible types. - - - union - (anonymous) - - - - __u32 - addr - Match a chip by this number, interpreted according -to the type field. - - - - char - name[32] - Match a chip by this name, interpreted according -to the type field. - - - -
- - - struct <structname>v4l2_dbg_chip_name</structname> - - &cs-str; - - - struct v4l2_dbg_match - match - How to match the chip, see . - - - char - name[32] - The name of the chip. - - - __u32 - flags - Set by the driver. If V4L2_CHIP_FL_READABLE -is set, then the driver supports reading registers from the device. If -V4L2_CHIP_FL_WRITABLE is set, then it supports writing registers. - - - __u32 - reserved[8] - Reserved fields, both application and driver must set these to 0. - - - -
- - - - Chip Match Types - - &cs-def; - - - V4L2_CHIP_MATCH_BRIDGE - 0 - Match the nth chip on the card, zero for the - bridge chip. Does not match sub-devices. - - - V4L2_CHIP_MATCH_I2C_DRIVER - 1 - Match an &i2c; chip by its driver name. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_I2C_ADDR - 2 - Match a chip by its 7 bit &i2c; bus address. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_AC97 - 3 - Match the nth anciliary AC97 chip. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_SUBDEV - 4 - Match the nth sub-device. - - - -
-
- - - &return-value; - - - - EINVAL - - The match_type is invalid or -no device could be matched. - - - - -
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml index db7844f2439f..d13bac9e2445 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml @@ -99,7 +99,7 @@ unchanged. match.addr selects the nth non-sub-device chip on the TV card. The number zero always selects the host chip, ⪚ the chip connected to the PCI or USB bus. You can find out which chips are -present with the &VIDIOC-DBG-G-CHIP-NAME; ioctl. +present with the &VIDIOC-DBG-G-CHIP-INFO; ioctl. When match.type is V4L2_CHIP_MATCH_I2C_DRIVER, @@ -109,7 +109,7 @@ For instance supported by the saa7127 driver, regardless of its &i2c; bus address. When multiple chips supported by the same driver are present, the effect of these ioctls is undefined. Again with the -&VIDIOC-DBG-G-CHIP-NAME; ioctl you can find out which &i2c; chips are +&VIDIOC-DBG-G-CHIP-INFO; ioctl you can find out which &i2c; chips are present. When match.type is @@ -131,14 +131,14 @@ on the TV card. Due to a flaw in the Linux &i2c; bus driver these ioctls may return successfully without actually reading or writing a register. To -catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-NAME; +catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-INFO; call confirming the presence of the selected &i2c; chip. These ioctls are optional, not all drivers may support them. However when a driver supports these ioctls it must also support -&VIDIOC-DBG-G-CHIP-NAME;. Conversely it may support -VIDIOC_DBG_G_CHIP_NAME but not these ioctls. +&VIDIOC-DBG-G-CHIP-INFO;. Conversely it may support +VIDIOC_DBG_G_CHIP_INFO but not these ioctls. VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER were introduced in Linux diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 39951f5731e1..c27c1f671396 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1332,8 +1332,8 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_chip_name(struct file *file, void *priv, - struct v4l2_dbg_chip_name *chip) +static int vidioc_g_chip_info(struct file *file, void *priv, + struct v4l2_dbg_chip_info *chip) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1797,7 +1797,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_chip_name = vidioc_g_chip_name, + .vidioc_g_chip_info = vidioc_g_chip_info, .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif @@ -1827,7 +1827,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, - .vidioc_g_chip_name = vidioc_g_chip_name, + .vidioc_g_chip_info = vidioc_g_chip_info, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 1c3b43cf773d..5923c5dfacd5 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -592,7 +592,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); #ifdef CONFIG_VIDEO_ADV_DEBUG - set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_INFO), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); #endif diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index c48d0acd8bb9..f81bda1a48ec 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -638,9 +638,9 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) p->ident, p->revision); } -static void v4l_print_dbg_chip_name(const void *arg, bool write_only) +static void v4l_print_dbg_chip_info(const void *arg, bool write_only) { - const struct v4l2_dbg_chip_name *p = arg; + const struct v4l2_dbg_chip_info *p = arg; pr_cont("type=%u, ", p->match.type); if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) @@ -1854,12 +1854,12 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, return ops->vidioc_g_chip_ident(file, fh, p); } -static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, +static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct video_device *vfd = video_devdata(file); - struct v4l2_dbg_chip_name *p = arg; + struct v4l2_dbg_chip_info *p = arg; struct v4l2_subdev *sd; int idx = 0; @@ -1875,8 +1875,8 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name)); else strlcpy(p->name, "bridge", sizeof(p->name)); - if (ops->vidioc_g_chip_name) - return ops->vidioc_g_chip_name(file, fh, arg); + if (ops->vidioc_g_chip_info) + return ops->vidioc_g_chip_info(file, fh, arg); if (p->match.addr) return -EINVAL; return 0; @@ -2116,7 +2116,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0), IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), - IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_NAME, v4l_dbg_g_chip_name, v4l_print_dbg_chip_name, INFO_FL_CLEAR(v4l2_dbg_chip_name, match)), + IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)), }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 6b917d69e408..931652f0e2af 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -244,8 +244,8 @@ struct v4l2_ioctl_ops { int (*vidioc_s_register) (struct file *file, void *fh, const struct v4l2_dbg_register *reg); - int (*vidioc_g_chip_name) (struct file *file, void *fh, - struct v4l2_dbg_chip_name *chip); + int (*vidioc_g_chip_info) (struct file *file, void *fh, + struct v4l2_dbg_chip_info *chip); #endif int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 4c941c103c44..be43b4659527 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1839,8 +1839,8 @@ struct v4l2_dbg_chip_ident { #define V4L2_CHIP_FL_READABLE (1 << 0) #define V4L2_CHIP_FL_WRITABLE (1 << 1) -/* VIDIOC_DBG_G_CHIP_NAME */ -struct v4l2_dbg_chip_name { +/* VIDIOC_DBG_G_CHIP_INFO */ +struct v4l2_dbg_chip_info { struct v4l2_dbg_match match; char name[32]; __u32 flags; @@ -1938,7 +1938,7 @@ struct v4l2_create_buffers { /* Experimental, meant for debugging, testing and internal use. Never use this ioctl in applications! - Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_NAME and + Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_INFO and will go away in the future. */ #define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) @@ -1976,7 +1976,7 @@ struct v4l2_create_buffers { /* Experimental, meant for debugging, testing and internal use. Never use these in applications! */ -#define VIDIOC_DBG_G_CHIP_NAME _IOWR('V', 102, struct v4l2_dbg_chip_name) +#define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info) /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ -- cgit v1.2.3 From b8399b83058848979538932473d817559f7ff8fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 11:53:55 -0300 Subject: [media] videodev2.h: increase size of 'reserved' array Increase the size of the 'reserved' array to give more room for future extensions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index be43b4659527..1282cd38e86a 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1844,7 +1844,7 @@ struct v4l2_dbg_chip_info { struct v4l2_dbg_match match; char name[32]; __u32 flags; - __u32 reserved[8]; + __u32 reserved[32]; } __attribute__ ((packed)); /** -- cgit v1.2.3 From 292a878720b26213bc773619715525e9f7a4f4a1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Mar 2013 15:26:36 -0300 Subject: [media] videodev2.h: fix incorrect V4L2_DV_FL_HALF_LINE bitmask This was set to 1 << 0 which is the same as V4L2_DV_FL_REDUCED_BLANKING. It should be 1 << 3 instead. Luckily interlaced formats are rarely used, which is why this bug wasn't seen until now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 1282cd38e86a..97fb392bb2d9 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1074,7 +1074,7 @@ struct v4l2_bt_timings { longer and field 2 is really one half-line shorter, so each field has exactly the same number of half-lines. Whether half-lines can be detected or used depends on the hardware. */ -#define V4L2_DV_FL_HALF_LINE (1 << 0) +#define V4L2_DV_FL_HALF_LINE (1 << 3) /** struct v4l2_dv_timings - DV timings -- cgit v1.2.3 From a7b74bd82a26379495e0e727d2c0fa9b0b97d917 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Mar 2013 14:31:34 -0300 Subject: [media] v4l2-dv-timings.h: add 480i59.94 and 576i50 CEA-861-E timings These formats are supported by the HDPVR, but they were missing in the list. Note that these formats are different from the common PAL/NTSC/SECAM formats since all color channels are transmitted separately and so there is no PAL or NTSC or SECAM color encoding involved. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/v4l2-dv-timings.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h index 9ef8172e5ed0..4e0c58d25ff0 100644 --- a/include/uapi/linux/v4l2-dv-timings.h +++ b/include/uapi/linux/v4l2-dv-timings.h @@ -42,6 +42,15 @@ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, 0) \ } +/* Note: these are the nominal timings, for HDMI links this format is typically + * double-clocked to meet the minimum pixelclock requirements. */ +#define V4L2_DV_BT_CEA_720X480I59_94 { \ + .type = V4L2_DV_BT_656_1120, \ + V4L2_INIT_BT_TIMINGS(720, 480, 1, 0, \ + 13500000, 19, 62, 57, 4, 3, 15, 4, 3, 16, \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ +} + #define V4L2_DV_BT_CEA_720X480P59_94 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \ @@ -49,6 +58,15 @@ V4L2_DV_BT_STD_CEA861, 0) \ } +/* Note: these are the nominal timings, for HDMI links this format is typically + * double-clocked to meet the minimum pixelclock requirements. */ +#define V4L2_DV_BT_CEA_720X576I50 { \ + .type = V4L2_DV_BT_656_1120, \ + V4L2_INIT_BT_TIMINGS(720, 576, 1, 0, \ + 13500000, 12, 63, 69, 2, 3, 19, 2, 3, 20, \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ +} + #define V4L2_DV_BT_CEA_720X576P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \ -- cgit v1.2.3 From 52f5ad6c5f16dedefbea447245192078484665ec Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 12 Apr 2013 13:59:02 -0300 Subject: [media] rc: add rc-reddo It is very similar than rc-msi-digivox-iii but new keytable is needed as there is one existing scancode mapped to different button. Also that one has less buttons. NEC extended protocol with address 0x61d6. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-reddo.c | 86 +++++++++++++++++++++++++++++++++++++ include/media/rc-map.h | 1 + 3 files changed, 88 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-reddo.c (limited to 'include') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 778661971aed..04baac4db200 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-hauppauge.o \ rc-rc6-mce.o \ rc-real-audio-220-32-keys.o \ + rc-reddo.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ rc-tbs-nec.o \ diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c new file mode 100644 index 000000000000..b80b336e9284 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-reddo.c @@ -0,0 +1,86 @@ +/* + * MSI DIGIVOX mini III remote controller keytable + * + * Copyright (C) 2013 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +/* + * Derived from MSI DIGIVOX mini III remote (rc-msi-digivox-iii.c) + * + * Differences between these remotes are: + * + * 1) scancode 0x61d601 is mapped to different button: + * MSI DIGIVOX mini III "Source" = KEY_VIDEO + * Reddo "EPG" = KEY_EPG + * + * 2) Reddo remote has less buttons. Missing buttons are: colored buttons, + * navigation buttons and main power button. + */ + +static struct rc_map_table reddo[] = { + { 0x61d601, KEY_EPG }, /* EPG */ + { 0x61d602, KEY_3 }, + { 0x61d604, KEY_1 }, + { 0x61d605, KEY_5 }, + { 0x61d606, KEY_6 }, + { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ + { 0x61d608, KEY_2 }, + { 0x61d609, KEY_CHANNELUP }, /* CH+ */ + { 0x61d60a, KEY_9 }, + { 0x61d60b, KEY_ZOOM }, /* Zoom */ + { 0x61d60c, KEY_7 }, + { 0x61d60d, KEY_8 }, + { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ + { 0x61d60f, KEY_4 }, + { 0x61d610, KEY_ESC }, /* [back up arrow] */ + { 0x61d611, KEY_0 }, + { 0x61d612, KEY_OK }, /* [enter arrow] */ + { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ + { 0x61d614, KEY_RECORD }, /* Rec */ + { 0x61d615, KEY_STOP }, /* Stop */ + { 0x61d616, KEY_PLAY }, /* Play */ + { 0x61d617, KEY_MUTE }, /* Mute */ + { 0x61d643, KEY_POWER2 }, /* [red power button] */ +}; + +static struct rc_map_list reddo_map = { + .map = { + .scan = reddo, + .size = ARRAY_SIZE(reddo), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_REDDO, + } +}; + +static int __init init_rc_map_reddo(void) +{ + return rc_map_register(&reddo_map); +} + +static void __exit exit_rc_map_reddo(void) +{ + rc_map_unregister(&reddo_map); +} + +module_init(init_rc_map_reddo) +module_exit(exit_rc_map_reddo) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index f74ee6f89711..5d5d3a30f04a 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -172,6 +172,7 @@ void rc_map_init(void); #define RC_MAP_RC5_TV "rc-rc5-tv" #define RC_MAP_RC6_MCE "rc-rc6-mce" #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" +#define RC_MAP_REDDO "rc-reddo" #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" #define RC_MAP_TBS_NEC "rc-tbs-nec" -- cgit v1.2.3 From 82cd0b278fddc1c0bc7e187ff82fd0e273520233 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 17 Apr 2013 06:05:18 -0300 Subject: Revert "[media] v4l2: Add a V4L2 driver for SI476X MFD" As requested by Andrey Smirnov , revert this patch. This reverts commit 30bac9110455402fa8888740c6819dd3daa2666f. Conflicts: drivers/media/radio/Kconfig drivers/media/radio/radio-si476x.c Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/si476x.txt | 187 ---- drivers/media/radio/Kconfig | 17 - drivers/media/radio/Makefile | 1 - drivers/media/radio/radio-si476x.c | 1599 ---------------------------------- include/media/si476x.h | 426 --------- 5 files changed, 2230 deletions(-) delete mode 100644 Documentation/video4linux/si476x.txt delete mode 100644 drivers/media/radio/radio-si476x.c delete mode 100644 include/media/si476x.h (limited to 'include') diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt deleted file mode 100644 index d1a08db2cbd9..000000000000 --- a/Documentation/video4linux/si476x.txt +++ /dev/null @@ -1,187 +0,0 @@ -SI476x Driver Readme ------------------------------------------------- - Copyright (C) 2013 Andrey Smirnov - -TODO for the driver ------------------------------- - -- According to the SiLabs' datasheet it is possible to update the - firmware of the radio chip in the run-time, thus bringing it to the - most recent version. Unfortunately I couldn't find any mentioning of - the said firmware update for the old chips that I tested the driver - against, so for chips like that the driver only exposes the old - functionality. - - -Parameters exposed over debugfs -------------------------------- -SI476x allow user to get multiple characteristics that can be very -useful for EoL testing/RF performance estimation, parameters that have -very little to do with V4L2 subsystem. Such parameters are exposed via -debugfs and can be accessed via regular file I/O operations. - -The drivers exposes following files: - -* /sys/kernel/debug//acf - This file contains ACF(Automatically Controlled Features) status - information. The contents of the file is binary data of the - following layout: - - Offset | Name | Description - ==================================================================== - 0x00 | blend_int | Flag, set when stereo separation has - | | crossed below the blend threshold - -------------------------------------------------------------------- - 0x01 | hblend_int | Flag, set when HiBlend cutoff - | | frequency is lower than threshold - -------------------------------------------------------------------- - 0x02 | hicut_int | Flag, set when HiCut cutoff - | | frequency is lower than threshold - -------------------------------------------------------------------- - 0x03 | chbw_int | Flag, set when channel filter - | | bandwidth is less than threshold - -------------------------------------------------------------------- - 0x04 | softmute_int | Flag indicating that softmute - | | attenuation has increased above - | | softmute threshold - -------------------------------------------------------------------- - 0x05 | smute | 0 - Audio is not soft muted - | | 1 - Audio is soft muted - -------------------------------------------------------------------- - 0x06 | smattn | Soft mute attenuation level in dB - -------------------------------------------------------------------- - 0x07 | chbw | Channel filter bandwidth in kHz - -------------------------------------------------------------------- - 0x08 | hicut | HiCut cutoff frequency in units of - | | 100Hz - -------------------------------------------------------------------- - 0x09 | hiblend | HiBlend cutoff frequency in units - | | of 100 Hz - -------------------------------------------------------------------- - 0x10 | pilot | 0 - Stereo pilot is not present - | | 1 - Stereo pilot is present - -------------------------------------------------------------------- - 0x11 | stblend | Stereo blend in % - -------------------------------------------------------------------- - - -* /sys/kernel/debug//rds_blckcnt - This file contains statistics about RDS receptions. It's binary data - has the following layout: - - Offset | Name | Description - ==================================================================== - 0x00 | expected | Number of expected RDS blocks - -------------------------------------------------------------------- - 0x02 | received | Number of received RDS blocks - -------------------------------------------------------------------- - 0x04 | uncorrectable | Number of uncorrectable RDS blocks - -------------------------------------------------------------------- - -* /sys/kernel/debug//agc - This file contains information about parameters pertaining to - AGC(Automatic Gain Control) - - The layout is: - Offset | Name | Description - ==================================================================== - 0x00 | mxhi | 0 - FM Mixer PD high threshold is - | | not tripped - | | 1 - FM Mixer PD high threshold is - | | tripped - -------------------------------------------------------------------- - 0x01 | mxlo | ditto for FM Mixer PD low - -------------------------------------------------------------------- - 0x02 | lnahi | ditto for FM LNA PD high - -------------------------------------------------------------------- - 0x03 | lnalo | ditto for FM LNA PD low - -------------------------------------------------------------------- - 0x04 | fmagc1 | FMAGC1 attenuator resistance - | | (see datasheet for more detail) - -------------------------------------------------------------------- - 0x05 | fmagc2 | ditto for FMAGC2 - -------------------------------------------------------------------- - 0x06 | pgagain | PGA gain in dB - -------------------------------------------------------------------- - 0x07 | fmwblang | FM/WB LNA Gain in dB - -------------------------------------------------------------------- - -* /sys/kernel/debug//rsq - This file contains information about parameters pertaining to - RSQ(Received Signal Quality) - - The layout is: - Offset | Name | Description - ==================================================================== - 0x00 | multhint | 0 - multipath value has not crossed - | | the Multipath high threshold - | | 1 - multipath value has crossed - | | the Multipath high threshold - -------------------------------------------------------------------- - 0x01 | multlint | ditto for Multipath low threshold - -------------------------------------------------------------------- - 0x02 | snrhint | 0 - received signal's SNR has not - | | crossed high threshold - | | 1 - received signal's SNR has - | | crossed high threshold - -------------------------------------------------------------------- - 0x03 | snrlint | ditto for low threshold - -------------------------------------------------------------------- - 0x04 | rssihint | ditto for RSSI high threshold - -------------------------------------------------------------------- - 0x05 | rssilint | ditto for RSSI low threshold - -------------------------------------------------------------------- - 0x06 | bltf | Flag indicating if seek command - | | reached/wrapped seek band limit - -------------------------------------------------------------------- - 0x07 | snr_ready | Indicates that SNR metrics is ready - -------------------------------------------------------------------- - 0x08 | rssiready | ditto for RSSI metrics - -------------------------------------------------------------------- - 0x09 | injside | 0 - Low-side injection is being used - | | 1 - High-side injection is used - -------------------------------------------------------------------- - 0x10 | afcrl | Flag indicating if AFC rails - -------------------------------------------------------------------- - 0x11 | valid | Flag indicating if channel is valid - -------------------------------------------------------------------- - 0x12 | readfreq | Current tuned frequency - -------------------------------------------------------------------- - 0x14 | freqoff | Singed frequency offset in units of - | | 2ppm - -------------------------------------------------------------------- - 0x15 | rssi | Signed value of RSSI in dBuV - -------------------------------------------------------------------- - 0x16 | snr | Signed RF SNR in dB - -------------------------------------------------------------------- - 0x17 | issi | Signed Image Strength Signal - | | indicator - -------------------------------------------------------------------- - 0x18 | lassi | Signed Low side adjacent Channel - | | Strength indicator - -------------------------------------------------------------------- - 0x19 | hassi | ditto fpr High side - -------------------------------------------------------------------- - 0x20 | mult | Multipath indicator - -------------------------------------------------------------------- - 0x21 | dev | Frequency deviation - -------------------------------------------------------------------- - 0x24 | assi | Adjascent channel SSI - -------------------------------------------------------------------- - 0x25 | usn | Ultrasonic noise indicator - -------------------------------------------------------------------- - 0x26 | pilotdev | Pilot deviation in units of 100 Hz - -------------------------------------------------------------------- - 0x27 | rdsdev | ditto for RDS - -------------------------------------------------------------------- - 0x28 | assidev | ditto for ASSI - -------------------------------------------------------------------- - 0x29 | strongdev | Frequency deviation - -------------------------------------------------------------------- - 0x30 | rdspi | RDS PI code - -------------------------------------------------------------------- - -* /sys/kernel/debug//rsq_primary - This file contains information about parameters pertaining to - RSQ(Received Signal Quality) for primary tuner only. Layout is as - the one above. diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index fef427e386c1..24e64a09884c 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -18,23 +18,6 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" -config RADIO_SI476X - tristate "Silicon Laboratories Si476x I2C FM Radio" - depends on I2C && VIDEO_V4L2 && SND && SND_SOC - select MFD_CORE - select MFD_SI476X_CORE - select SND_SOC_SI476X - ---help--- - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-si476x. - config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 0dcdb320cfc7..303eaebdb85a 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o -obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c deleted file mode 100644 index 9430c6a29937..000000000000 --- a/drivers/media/radio/radio-si476x.c +++ /dev/null @@ -1,1599 +0,0 @@ -/* - * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define FM_FREQ_RANGE_LOW 64000000 -#define FM_FREQ_RANGE_HIGH 108000000 - -#define AM_FREQ_RANGE_LOW 520000 -#define AM_FREQ_RANGE_HIGH 30000000 - -#define PWRLINEFLTR (1 << 8) - -#define FREQ_MUL (10000000 / 625) - -#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) - -#define DRIVER_NAME "si476x-radio" -#define DRIVER_CARD "SI476x AM/FM Receiver" - -enum si476x_freq_bands { - SI476X_BAND_FM, - SI476X_BAND_AM, -}; - -static const struct v4l2_frequency_band si476x_bands[] = { - [SI476X_BAND_FM] = { - .type = V4L2_TUNER_RADIO, - .index = SI476X_BAND_FM, - .capability = V4L2_TUNER_CAP_LOW - | V4L2_TUNER_CAP_STEREO - | V4L2_TUNER_CAP_RDS - | V4L2_TUNER_CAP_RDS_BLOCK_IO - | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 64 * FREQ_MUL, - .rangehigh = 108 * FREQ_MUL, - .modulation = V4L2_BAND_MODULATION_FM, - }, - [SI476X_BAND_AM] = { - .type = V4L2_TUNER_RADIO, - .index = SI476X_BAND_AM, - .capability = V4L2_TUNER_CAP_LOW - | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 0.52 * FREQ_MUL, - .rangehigh = 30 * FREQ_MUL, - .modulation = V4L2_BAND_MODULATION_AM, - }, -}; - -static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band) -{ - return freq >= si476x_bands[band].rangelow && - freq <= si476x_bands[band].rangehigh; -} - -static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high, - int band) -{ - return low >= si476x_bands[band].rangelow && - high <= si476x_bands[band].rangehigh; -} - -static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl); -static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl); - -enum phase_diversity_modes_idx { - SI476X_IDX_PHDIV_DISABLED, - SI476X_IDX_PHDIV_PRIMARY_COMBINING, - SI476X_IDX_PHDIV_PRIMARY_ANTENNA, - SI476X_IDX_PHDIV_SECONDARY_ANTENNA, - SI476X_IDX_PHDIV_SECONDARY_COMBINING, -}; - -static const char * const phase_diversity_modes[] = { - [SI476X_IDX_PHDIV_DISABLED] = "Disabled", - [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary", - [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna", - [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna", - [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary", -}; - -static inline enum phase_diversity_modes_idx -si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode) -{ - switch (mode) { - default: /* FALLTHROUGH */ - case SI476X_PHDIV_DISABLED: - return SI476X_IDX_PHDIV_DISABLED; - case SI476X_PHDIV_PRIMARY_COMBINING: - return SI476X_IDX_PHDIV_PRIMARY_COMBINING; - case SI476X_PHDIV_PRIMARY_ANTENNA: - return SI476X_IDX_PHDIV_PRIMARY_ANTENNA; - case SI476X_PHDIV_SECONDARY_ANTENNA: - return SI476X_IDX_PHDIV_SECONDARY_ANTENNA; - case SI476X_PHDIV_SECONDARY_COMBINING: - return SI476X_IDX_PHDIV_SECONDARY_COMBINING; - } -} - -static inline enum si476x_phase_diversity_mode -si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx) -{ - static const int idx_to_value[] = { - [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED, - [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING, - [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA, - [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA, - [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING, - }; - - return idx_to_value[idx]; -} - -static const struct v4l2_ctrl_ops si476x_ctrl_ops = { - .g_volatile_ctrl = si476x_radio_g_volatile_ctrl, - .s_ctrl = si476x_radio_s_ctrl, -}; - - -enum si476x_ctrl_idx { - SI476X_IDX_RSSI_THRESHOLD, - SI476X_IDX_SNR_THRESHOLD, - SI476X_IDX_MAX_TUNE_ERROR, - SI476X_IDX_HARMONICS_COUNT, - SI476X_IDX_DIVERSITY_MODE, - SI476X_IDX_INTERCHIP_LINK, -}; -static struct v4l2_ctrl_config si476x_ctrls[] = { - - /** - * SI476X during its station seeking(or tuning) process uses several - * parameters to detrmine if "the station" is valid: - * - * - Signal's SNR(in dBuV) must be lower than - * #V4L2_CID_SI476X_SNR_THRESHOLD - * - Signal's RSSI(in dBuV) must be greater than - * #V4L2_CID_SI476X_RSSI_THRESHOLD - * - Signal's frequency deviation(in units of 2ppm) must not be - * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR - */ - [SI476X_IDX_RSSI_THRESHOLD] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_RSSI_THRESHOLD, - .name = "Valid RSSI Threshold", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = -128, - .max = 127, - .step = 1, - }, - [SI476X_IDX_SNR_THRESHOLD] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_SNR_THRESHOLD, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Valid SNR Threshold", - .min = -128, - .max = 127, - .step = 1, - }, - [SI476X_IDX_MAX_TUNE_ERROR] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_MAX_TUNE_ERROR, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Max Tune Errors", - .min = 0, - .max = 126 * 2, - .step = 2, - }, - - /** - * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics - * built-in power-line noise supression filter is to reject - * during AM-mode operation. - */ - [SI476X_IDX_HARMONICS_COUNT] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_HARMONICS_COUNT, - .type = V4L2_CTRL_TYPE_INTEGER, - - .name = "Count of Harmonics to Reject", - .min = 0, - .max = 20, - .step = 1, - }, - - /** - * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which - * two tuners working in diversity mode are to work in. - * - * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled - * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is - * on, primary tuner's antenna is the main one. - * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is - * off, primary tuner's antenna is the main one. - * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is - * off, secondary tuner's antenna is the main one. - * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is - * on, secondary tuner's antenna is the main one. - */ - [SI476X_IDX_DIVERSITY_MODE] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_DIVERSITY_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Phase Diversity Mode", - .qmenu = phase_diversity_modes, - .min = 0, - .max = ARRAY_SIZE(phase_diversity_modes) - 1, - }, - - /** - * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in - * diversity mode indicator. Allows user to determine if two - * chips working in diversity mode have established a link - * between each other and if the system as a whole uses - * signals from both antennas to receive FM radio. - */ - [SI476X_IDX_INTERCHIP_LINK] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_INTERCHIP_LINK, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, - .name = "Inter-Chip Link", - .min = 0, - .max = 1, - .step = 1, - }, -}; - -struct si476x_radio; - -/** - * struct si476x_radio_ops - vtable of tuner functions - * - * This table holds pointers to functions implementing particular - * operations depending on the mode in which the tuner chip was - * configured to start in. If the function is not supported - * corresponding element is set to #NULL. - * - * @tune_freq: Tune chip to a specific frequency - * @seek_start: Star station seeking - * @rsq_status: Get Recieved Signal Quality(RSQ) status - * @rds_blckcnt: Get recived RDS blocks count - * @phase_diversity: Change phase diversity mode of the tuner - * @phase_div_status: Get phase diversity mode status - * @acf_status: Get the status of Automatically Controlled - * Features(ACF) - * @agc_status: Get Automatic Gain Control(AGC) status - */ -struct si476x_radio_ops { - int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *); - int (*seek_start)(struct si476x_core *, bool, bool); - int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); - int (*rds_blckcnt)(struct si476x_core *, bool, - struct si476x_rds_blockcount_report *); - - int (*phase_diversity)(struct si476x_core *, - enum si476x_phase_diversity_mode); - int (*phase_div_status)(struct si476x_core *); - int (*acf_status)(struct si476x_core *, - struct si476x_acf_status_report *); - int (*agc_status)(struct si476x_core *, - struct si476x_agc_status_report *); -}; - -/** - * struct si476x_radio - radio device - * - * @core: Pointer to underlying core device - * @videodev: Pointer to video device created by V4L2 subsystem - * @ops: Vtable of functions. See struct si476x_radio_ops for details - * @kref: Reference counter - * @core_lock: An r/w semaphore to brebvent the deletion of underlying - * core structure is the radio device is being used - */ -struct si476x_radio { - struct v4l2_device v4l2dev; - struct video_device videodev; - struct v4l2_ctrl_handler ctrl_handler; - - struct si476x_core *core; - /* This field should not be accesses unless core lock is held */ - const struct si476x_radio_ops *ops; - - struct dentry *debugfs; - u32 audmode; -}; - -static inline struct si476x_radio * -v4l2_dev_to_radio(struct v4l2_device *d) -{ - return container_of(d, struct si476x_radio, v4l2dev); -} - -static inline struct si476x_radio * -v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) -{ - return container_of(d, struct si476x_radio, ctrl_handler); -} - -/* - * si476x_vidioc_querycap - query device capabilities - */ -static int si476x_radio_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct si476x_radio *radio = video_drvdata(file); - - strlcpy(capability->driver, radio->v4l2dev.name, - sizeof(capability->driver)); - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - snprintf(capability->bus_info, sizeof(capability->bus_info), - "platform:%s", radio->v4l2dev.name); - - capability->device_caps = V4L2_CAP_TUNER - | V4L2_CAP_RADIO - | V4L2_CAP_HW_FREQ_SEEK; - - si476x_core_lock(radio->core); - if (!si476x_core_is_a_secondary_tuner(radio->core)) - capability->device_caps |= V4L2_CAP_RDS_CAPTURE - | V4L2_CAP_READWRITE; - si476x_core_unlock(radio->core); - - capability->capabilities = capability->device_caps - | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int si476x_radio_enum_freq_bands(struct file *file, void *priv, - struct v4l2_frequency_band *band) -{ - int err; - struct si476x_radio *radio = video_drvdata(file); - - if (band->tuner != 0) - return -EINVAL; - - switch (radio->core->chip_id) { - /* AM/FM tuners -- all bands are supported */ - case SI476X_CHIP_SI4761: - case SI476X_CHIP_SI4764: - if (band->index < ARRAY_SIZE(si476x_bands)) { - *band = si476x_bands[band->index]; - err = 0; - } else { - err = -EINVAL; - } - break; - /* FM companion tuner chips -- only FM bands are - * supported */ - case SI476X_CHIP_SI4768: - if (band->index == SI476X_BAND_FM) { - *band = si476x_bands[band->index]; - err = 0; - } else { - err = -EINVAL; - } - break; - default: - err = -EINVAL; - } - - return err; -} - -static int si476x_radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - int err; - struct si476x_rsq_status_report report; - struct si476x_radio *radio = video_drvdata(file); - - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = false, - }; - - if (tuner->index != 0) - return -EINVAL; - - tuner->type = V4L2_TUNER_RADIO; - tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies - * in multiples of - * 62.5 Hz */ - | V4L2_TUNER_CAP_STEREO - | V4L2_TUNER_CAP_HWSEEK_BOUNDED - | V4L2_TUNER_CAP_HWSEEK_WRAP - | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; - - si476x_core_lock(radio->core); - - if (si476x_core_is_a_secondary_tuner(radio->core)) { - strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); - tuner->rxsubchans = 0; - tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; - } else if (si476x_core_has_am(radio->core)) { - if (si476x_core_is_a_primary_tuner(radio->core)) - strlcpy(tuner->name, "AM/FM (primary)", - sizeof(tuner->name)); - else - strlcpy(tuner->name, "AM/FM", sizeof(tuner->name)); - - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO - | V4L2_TUNER_SUB_RDS; - tuner->capability |= V4L2_TUNER_CAP_RDS - | V4L2_TUNER_CAP_RDS_BLOCK_IO - | V4L2_TUNER_CAP_FREQ_BANDS; - - tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; - } else { - strlcpy(tuner->name, "FM", sizeof(tuner->name)); - tuner->rxsubchans = V4L2_TUNER_SUB_RDS; - tuner->capability |= V4L2_TUNER_CAP_RDS - | V4L2_TUNER_CAP_RDS_BLOCK_IO - | V4L2_TUNER_CAP_FREQ_BANDS; - tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; - } - - tuner->audmode = radio->audmode; - - tuner->afc = 1; - tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; - - err = radio->ops->rsq_status(radio->core, - &args, &report); - if (err < 0) { - tuner->signal = 0; - } else { - /* - * tuner->signal value range: 0x0000 .. 0xFFFF, - * report.rssi: -128 .. 127 - */ - tuner->signal = (report.rssi + 128) * 257; - } - si476x_core_unlock(radio->core); - - return err; -} - -static int si476x_radio_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *tuner) -{ - struct si476x_radio *radio = video_drvdata(file); - - if (tuner->index != 0) - return -EINVAL; - - if (tuner->audmode == V4L2_TUNER_MODE_MONO || - tuner->audmode == V4L2_TUNER_MODE_STEREO) - radio->audmode = tuner->audmode; - else - radio->audmode = V4L2_TUNER_MODE_STEREO; - - return 0; -} - -static int si476x_radio_init_vtable(struct si476x_radio *radio, - enum si476x_func func) -{ - static const struct si476x_radio_ops fm_ops = { - .tune_freq = si476x_core_cmd_fm_tune_freq, - .seek_start = si476x_core_cmd_fm_seek_start, - .rsq_status = si476x_core_cmd_fm_rsq_status, - .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, - .phase_diversity = si476x_core_cmd_fm_phase_diversity, - .phase_div_status = si476x_core_cmd_fm_phase_div_status, - .acf_status = si476x_core_cmd_fm_acf_status, - .agc_status = si476x_core_cmd_agc_status, - }; - - static const struct si476x_radio_ops am_ops = { - .tune_freq = si476x_core_cmd_am_tune_freq, - .seek_start = si476x_core_cmd_am_seek_start, - .rsq_status = si476x_core_cmd_am_rsq_status, - .rds_blckcnt = NULL, - .phase_diversity = NULL, - .phase_div_status = NULL, - .acf_status = si476x_core_cmd_am_acf_status, - .agc_status = NULL, - }; - - switch (func) { - case SI476X_FUNC_FM_RECEIVER: - radio->ops = &fm_ops; - return 0; - - case SI476X_FUNC_AM_RECEIVER: - radio->ops = &am_ops; - return 0; - default: - WARN(1, "Unexpected tuner function value\n"); - return -EINVAL; - } -} - -static int si476x_radio_pretune(struct si476x_radio *radio, - enum si476x_func func) -{ - int retval; - - struct si476x_tune_freq_args args = { - .zifsr = false, - .hd = false, - .injside = SI476X_INJSIDE_AUTO, - .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, - .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, - .antcap = 0, - }; - - switch (func) { - case SI476X_FUNC_FM_RECEIVER: - args.freq = v4l2_to_si476x(radio->core, - 92 * FREQ_MUL); - retval = radio->ops->tune_freq(radio->core, &args); - break; - case SI476X_FUNC_AM_RECEIVER: - args.freq = v4l2_to_si476x(radio->core, - 0.6 * FREQ_MUL); - retval = radio->ops->tune_freq(radio->core, &args); - break; - default: - WARN(1, "Unexpected tuner function value\n"); - retval = -EINVAL; - } - - return retval; -} -static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, - enum si476x_func func) -{ - int err; - - /* regcache_mark_dirty(radio->core->regmap); */ - 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; - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_AUDIO_DEEMPHASIS, - SI476X_PROP_AUDIO_PWR_LINE_FILTER); - if (err < 0) - return err; - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_INT_CTL_ENABLE, - SI476X_PROP_INT_CTL_ENABLE); - if (err < 0) - return err; - - /* - * Is there any point in restoring SNR and the like - * when switching between AM/FM? - */ - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_VALID_MAX_TUNE_ERROR, - SI476X_PROP_VALID_MAX_TUNE_ERROR); - if (err < 0) - return err; - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_VALID_SNR_THRESHOLD, - SI476X_PROP_VALID_RSSI_THRESHOLD); - if (err < 0) - return err; - - if (func == SI476X_FUNC_FM_RECEIVER) { - if (si476x_core_has_diversity(radio->core)) { - err = si476x_core_cmd_fm_phase_diversity(radio->core, - radio->core->diversity_mode); - if (err < 0) - return err; - } - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, - SI476X_PROP_FM_RDS_CONFIG); - if (err < 0) - return err; - } - - return si476x_radio_init_vtable(radio, func); - -} - -static int si476x_radio_change_func(struct si476x_radio *radio, - enum si476x_func func) -{ - int err; - bool soft; - /* - * Since power/up down is a very time consuming operation, - * try to avoid doing it if the requested mode matches the one - * the tuner is in - */ - if (func == radio->core->power_up_parameters.func) - return 0; - - soft = true; - err = si476x_core_stop(radio->core, soft); - if (err < 0) { - /* - * OK, if the chip does not want to play nice let's - * try to reset it in more brutal way - */ - soft = false; - err = si476x_core_stop(radio->core, soft); - if (err < 0) - return err; - } - /* - Set the desired radio tuner function - */ - radio->core->power_up_parameters.func = func; - - err = si476x_core_start(radio->core, soft); - if (err < 0) - return err; - - /* - * No need to do the rest of manipulations for the bootlader - * mode - */ - if (func != SI476X_FUNC_FM_RECEIVER && - func != SI476X_FUNC_AM_RECEIVER) - return err; - - return si476x_radio_do_post_powerup_init(radio, func); -} - -static int si476x_radio_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - int err; - struct si476x_radio *radio = video_drvdata(file); - - if (f->tuner != 0 || - f->type != V4L2_TUNER_RADIO) - return -EINVAL; - - si476x_core_lock(radio->core); - - if (radio->ops->rsq_status) { - struct si476x_rsq_status_report report; - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = true, - .cancel = false, - .stcack = false, - }; - - err = radio->ops->rsq_status(radio->core, &args, &report); - if (!err) - f->frequency = si476x_to_v4l2(radio->core, - report.readfreq); - } else { - err = -EINVAL; - } - - si476x_core_unlock(radio->core); - - return err; -} - -static int si476x_radio_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f) -{ - int err; - u32 freq = f->frequency; - struct si476x_tune_freq_args args; - struct si476x_radio *radio = video_drvdata(file); - - const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + - si476x_bands[SI476X_BAND_FM].rangelow) / 2; - const int band = (freq > midrange) ? - SI476X_BAND_FM : SI476X_BAND_AM; - const enum si476x_func func = (band == SI476X_BAND_AM) ? - SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; - - if (f->tuner != 0 || - f->type != V4L2_TUNER_RADIO) - return -EINVAL; - - si476x_core_lock(radio->core); - - freq = clamp(freq, - si476x_bands[band].rangelow, - si476x_bands[band].rangehigh); - - if (si476x_radio_freq_is_inside_of_the_band(freq, - SI476X_BAND_AM) && - (!si476x_core_has_am(radio->core) || - si476x_core_is_a_secondary_tuner(radio->core))) { - err = -EINVAL; - goto unlock; - } - - err = si476x_radio_change_func(radio, func); - if (err < 0) - goto unlock; - - args.zifsr = false; - args.hd = false; - args.injside = SI476X_INJSIDE_AUTO; - args.freq = v4l2_to_si476x(radio->core, freq); - args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; - args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; - args.antcap = 0; - - err = radio->ops->tune_freq(radio->core, &args); - -unlock: - si476x_core_unlock(radio->core); - return err; -} - -static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, - const struct v4l2_hw_freq_seek *seek) -{ - int err; - enum si476x_func func; - u32 rangelow, rangehigh; - struct si476x_radio *radio = video_drvdata(file); - - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - if (seek->tuner != 0 || - seek->type != V4L2_TUNER_RADIO) - return -EINVAL; - - si476x_core_lock(radio->core); - - if (!seek->rangelow) { - err = regmap_read(radio->core->regmap, - SI476X_PROP_SEEK_BAND_BOTTOM, - &rangelow); - if (!err) - rangelow = si476x_to_v4l2(radio->core, rangelow); - else - goto unlock; - } - if (!seek->rangehigh) { - err = regmap_read(radio->core->regmap, - SI476X_PROP_SEEK_BAND_TOP, - &rangehigh); - if (!err) - rangehigh = si476x_to_v4l2(radio->core, rangehigh); - else - goto unlock; - } - - if (rangelow > rangehigh) { - err = -EINVAL; - goto unlock; - } - - if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, - SI476X_BAND_FM)) { - func = SI476X_FUNC_FM_RECEIVER; - - } else if (si476x_core_has_am(radio->core) && - si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, - SI476X_BAND_AM)) { - func = SI476X_FUNC_AM_RECEIVER; - } else { - err = -EINVAL; - goto unlock; - } - - err = si476x_radio_change_func(radio, func); - if (err < 0) - goto unlock; - - if (seek->rangehigh) { - err = regmap_write(radio->core->regmap, - SI476X_PROP_SEEK_BAND_TOP, - v4l2_to_si476x(radio->core, - seek->rangehigh)); - if (err) - goto unlock; - } - if (seek->rangelow) { - err = regmap_write(radio->core->regmap, - SI476X_PROP_SEEK_BAND_BOTTOM, - v4l2_to_si476x(radio->core, - seek->rangelow)); - if (err) - goto unlock; - } - if (seek->spacing) { - err = regmap_write(radio->core->regmap, - SI476X_PROP_SEEK_FREQUENCY_SPACING, - v4l2_to_si476x(radio->core, - seek->spacing)); - if (err) - goto unlock; - } - - err = radio->ops->seek_start(radio->core, - seek->seek_upward, - seek->wrap_around); -unlock: - si476x_core_unlock(radio->core); - - - - return err; -} - -static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - int retval; - struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); - - si476x_core_lock(radio->core); - - switch (ctrl->id) { - case V4L2_CID_SI476X_INTERCHIP_LINK: - if (si476x_core_has_diversity(radio->core)) { - if (radio->ops->phase_diversity) { - retval = radio->ops->phase_div_status(radio->core); - if (retval < 0) - break; - - ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); - retval = 0; - break; - } else { - retval = -ENOTTY; - break; - } - } - retval = -EINVAL; - break; - default: - retval = -EINVAL; - break; - } - si476x_core_unlock(radio->core); - return retval; - -} - -static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) -{ - int retval; - enum si476x_phase_diversity_mode mode; - struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); - - si476x_core_lock(radio->core); - - switch (ctrl->id) { - case V4L2_CID_SI476X_HARMONICS_COUNT: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_HARMONICS_MASK, - ctrl->val); - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (ctrl->val) { - case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_ENABLE_MASK, - 0); - break; - case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_GRID_MASK, - SI476X_PROP_PWR_GRID_50HZ); - break; - case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_GRID_MASK, - SI476X_PROP_PWR_GRID_60HZ); - break; - default: - retval = -EINVAL; - break; - } - break; - case V4L2_CID_SI476X_RSSI_THRESHOLD: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_VALID_RSSI_THRESHOLD, - ctrl->val); - break; - case V4L2_CID_SI476X_SNR_THRESHOLD: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_VALID_SNR_THRESHOLD, - ctrl->val); - break; - case V4L2_CID_SI476X_MAX_TUNE_ERROR: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_VALID_MAX_TUNE_ERROR, - ctrl->val); - break; - case V4L2_CID_RDS_RECEPTION: - /* - * It looks like RDS related properties are - * inaccesable when tuner is in AM mode, so cache the - * changes - */ - if (si476x_core_is_in_am_receiver_mode(radio->core)) - regcache_cache_only(radio->core->regmap, true); - - if (ctrl->val) { - retval = regmap_write(radio->core->regmap, - SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, - radio->core->rds_fifo_depth); - if (retval < 0) - break; - - if (radio->core->client->irq) { - retval = regmap_write(radio->core->regmap, - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, - SI476X_RDSRECV); - if (retval < 0) - break; - } - - /* Drain RDS FIFO before enabling RDS processing */ - retval = si476x_core_cmd_fm_rds_status(radio->core, - false, - true, - true, - NULL); - if (retval < 0) - break; - - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_FM_RDS_CONFIG, - SI476X_PROP_RDSEN_MASK, - SI476X_PROP_RDSEN); - } else { - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_FM_RDS_CONFIG, - SI476X_PROP_RDSEN_MASK, - !SI476X_PROP_RDSEN); - } - - if (si476x_core_is_in_am_receiver_mode(radio->core)) - regcache_cache_only(radio->core->regmap, false); - break; - case V4L2_CID_TUNE_DEEMPHASIS: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_AUDIO_DEEMPHASIS, - ctrl->val); - break; - - case V4L2_CID_SI476X_DIVERSITY_MODE: - mode = si476x_phase_diversity_idx_to_mode(ctrl->val); - - if (mode == radio->core->diversity_mode) { - retval = 0; - break; - } - - if (si476x_core_is_in_am_receiver_mode(radio->core)) { - /* - * Diversity cannot be configured while tuner - * is in AM mode so save the changes and carry on. - */ - radio->core->diversity_mode = mode; - retval = 0; - } else { - retval = radio->ops->phase_diversity(radio->core, mode); - if (!retval) - radio->core->diversity_mode = mode; - } - break; - - default: - retval = -EINVAL; - break; - } - - si476x_core_unlock(radio->core); - - return retval; -} - -static int si476x_radio_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - if (chip->match.type == V4L2_CHIP_MATCH_HOST && - v4l2_chip_match_host(&chip->match)) - return 0; - return -EINVAL; -} - - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int si476x_radio_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - int err; - unsigned int value; - struct si476x_radio *radio = video_drvdata(file); - - si476x_core_lock(radio->core); - reg->size = 2; - err = regmap_read(radio->core->regmap, - (unsigned int)reg->reg, &value); - reg->val = value; - si476x_core_unlock(radio->core); - - return err; -} -static int si476x_radio_s_register(struct file *file, void *fh, - const struct v4l2_dbg_register *reg) -{ - - int err; - struct si476x_radio *radio = video_drvdata(file); - - si476x_core_lock(radio->core); - err = regmap_write(radio->core->regmap, - (unsigned int)reg->reg, - (unsigned int)reg->val); - si476x_core_unlock(radio->core); - - return err; -} -#endif - -static int si476x_radio_fops_open(struct file *file) -{ - struct si476x_radio *radio = video_drvdata(file); - int err; - - err = v4l2_fh_open(file); - if (err) - return err; - - if (v4l2_fh_is_singular_file(file)) { - si476x_core_lock(radio->core); - err = si476x_core_set_power_state(radio->core, - SI476X_POWER_UP_FULL); - if (err < 0) - goto done; - - err = si476x_radio_do_post_powerup_init(radio, - radio->core->power_up_parameters.func); - if (err < 0) - goto power_down; - - err = si476x_radio_pretune(radio, - radio->core->power_up_parameters.func); - if (err < 0) - goto power_down; - - si476x_core_unlock(radio->core); - /*Must be done after si476x_core_unlock to prevent a deadlock*/ - v4l2_ctrl_handler_setup(&radio->ctrl_handler); - } - - return err; - -power_down: - si476x_core_set_power_state(radio->core, - SI476X_POWER_DOWN); -done: - si476x_core_unlock(radio->core); - v4l2_fh_release(file); - - return err; -} - -static int si476x_radio_fops_release(struct file *file) -{ - int err; - struct si476x_radio *radio = video_drvdata(file); - - if (v4l2_fh_is_singular_file(file) && - atomic_read(&radio->core->is_alive)) - si476x_core_set_power_state(radio->core, - SI476X_POWER_DOWN); - - err = v4l2_fh_release(file); - - return err; -} - -static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t rval; - size_t fifo_len; - unsigned int copied; - - struct si476x_radio *radio = video_drvdata(file); - - /* block if no new data available */ - if (kfifo_is_empty(&radio->core->rds_fifo)) { - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - rval = wait_event_interruptible(radio->core->rds_read_queue, - (!kfifo_is_empty(&radio->core->rds_fifo) || - !atomic_read(&radio->core->is_alive))); - if (rval < 0) - return -EINTR; - - if (!atomic_read(&radio->core->is_alive)) - return -ENODEV; - } - - fifo_len = kfifo_len(&radio->core->rds_fifo); - - if (kfifo_to_user(&radio->core->rds_fifo, buf, - min(fifo_len, count), - &copied) != 0) { - dev_warn(&radio->videodev.dev, - "Error during FIFO to userspace copy\n"); - rval = -EIO; - } else { - rval = (ssize_t)copied; - } - - return rval; -} - -static unsigned int si476x_radio_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct si476x_radio *radio = video_drvdata(file); - unsigned long req_events = poll_requested_events(pts); - unsigned int err = v4l2_ctrl_poll(file, pts); - - if (req_events & (POLLIN | POLLRDNORM)) { - if (atomic_read(&radio->core->is_alive)) - poll_wait(file, &radio->core->rds_read_queue, pts); - - if (!atomic_read(&radio->core->is_alive)) - err = POLLHUP; - - if (!kfifo_is_empty(&radio->core->rds_fifo)) - err = POLLIN | POLLRDNORM; - } - - return err; -} - -static const struct v4l2_file_operations si476x_fops = { - .owner = THIS_MODULE, - .read = si476x_radio_fops_read, - .poll = si476x_radio_fops_poll, - .unlocked_ioctl = video_ioctl2, - .open = si476x_radio_fops_open, - .release = si476x_radio_fops_release, -}; - - -static const struct v4l2_ioctl_ops si4761_ioctl_ops = { - .vidioc_querycap = si476x_radio_querycap, - .vidioc_g_tuner = si476x_radio_g_tuner, - .vidioc_s_tuner = si476x_radio_s_tuner, - - .vidioc_g_frequency = si476x_radio_g_frequency, - .vidioc_s_frequency = si476x_radio_s_frequency, - .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, - .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - - .vidioc_g_chip_ident = si476x_radio_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = si476x_radio_g_register, - .vidioc_s_register = si476x_radio_s_register, -#endif -}; - - -static const struct video_device si476x_viddev_template = { - .fops = &si476x_fops, - .name = DRIVER_NAME, - .release = video_device_release_empty, -}; - - - -static ssize_t si476x_radio_read_acf_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_acf_status_report report; - - si476x_core_lock(radio->core); - if (radio->ops->acf_status) - err = radio->ops->acf_status(radio->core, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_acf_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_acf_blob, -}; - -static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_rds_blockcount_report report; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->rds_blckcnt(radio->core, true, - &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_rds_blckcnt_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_rds_blckcnt_blob, -}; - -static ssize_t si476x_radio_read_agc_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_agc_status_report report; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->agc_status(radio->core, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_agc_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_agc_blob, -}; - -static ssize_t si476x_radio_read_rsq_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_rsq_status_report report; - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = false, - }; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->rsq_status(radio->core, &args, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_rsq_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_rsq_blob, -}; - -static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_rsq_status_report report; - struct si476x_rsq_status_args args = { - .primary = true, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = false, - }; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->rsq_status(radio->core, &args, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_rsq_primary_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_rsq_primary_blob, -}; - - -static int si476x_radio_init_debugfs(struct si476x_radio *radio) -{ - struct dentry *dentry; - int ret; - - dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto exit; - } - radio->debugfs = dentry; - - dentry = debugfs_create_file("acf", S_IRUGO, - radio->debugfs, radio, &radio_acf_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("rds_blckcnt", S_IRUGO, - radio->debugfs, radio, - &radio_rds_blckcnt_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("agc", S_IRUGO, - radio->debugfs, radio, &radio_agc_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("rsq", S_IRUGO, - radio->debugfs, radio, &radio_rsq_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("rsq_primary", S_IRUGO, - radio->debugfs, radio, - &radio_rsq_primary_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - return 0; -cleanup: - debugfs_remove_recursive(radio->debugfs); -exit: - return ret; -} - - -static int si476x_radio_add_new_custom(struct si476x_radio *radio, - enum si476x_ctrl_idx idx) -{ - int rval; - struct v4l2_ctrl *ctrl; - - ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, - &si476x_ctrls[idx], - NULL); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) - dev_err(radio->v4l2dev.dev, - "Could not initialize '%s' control %d\n", - si476x_ctrls[idx].name, rval); - - return rval; -} - -static int si476x_radio_probe(struct platform_device *pdev) -{ - int rval; - struct si476x_radio *radio; - struct v4l2_ctrl *ctrl; - - static atomic_t instance = ATOMIC_INIT(0); - - radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); - if (!radio) - return -ENOMEM; - - radio->core = i2c_mfd_cell_to_core(&pdev->dev); - - v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); - - rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); - if (rval) { - dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); - return rval; - } - - memcpy(&radio->videodev, &si476x_viddev_template, - sizeof(struct video_device)); - - radio->videodev.v4l2_dev = &radio->v4l2dev; - radio->videodev.ioctl_ops = &si4761_ioctl_ops; - - video_set_drvdata(&radio->videodev, radio); - platform_set_drvdata(pdev, radio); - - set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); - - radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; - v4l2_ctrl_handler_init(&radio->ctrl_handler, - 1 + ARRAY_SIZE(si476x_ctrls)); - - if (si476x_core_has_am(radio->core)) { - ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, - &si476x_ctrl_ops, - V4L2_CID_POWER_LINE_FREQUENCY, - V4L2_CID_POWER_LINE_FREQUENCY_60HZ, - 0, 0); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) { - dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", - rval); - goto exit; - } - - rval = si476x_radio_add_new_custom(radio, - SI476X_IDX_HARMONICS_COUNT); - if (rval < 0) - goto exit; - } - - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); - if (rval < 0) - goto exit; - - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); - if (rval < 0) - goto exit; - - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); - if (rval < 0) - goto exit; - - ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, - &si476x_ctrl_ops, - V4L2_CID_TUNE_DEEMPHASIS, - V4L2_DEEMPHASIS_75_uS, 0, 0); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) { - dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", - rval); - goto exit; - } - - ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, - V4L2_CID_RDS_RECEPTION, - 0, 1, 1, 1); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) { - dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", - rval); - goto exit; - } - - if (si476x_core_has_diversity(radio->core)) { - si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = - si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); - si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); - if (rval < 0) - goto exit; - - si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); - if (rval < 0) - goto exit; - } - - /* register video device */ - rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); - if (rval < 0) { - dev_err(&pdev->dev, "Could not register video device\n"); - goto exit; - } - - rval = si476x_radio_init_debugfs(radio); - if (rval < 0) { - dev_err(&pdev->dev, "Could not creat debugfs interface\n"); - goto exit; - } - - return 0; -exit: - v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); - return rval; -} - -static int si476x_radio_remove(struct platform_device *pdev) -{ - struct si476x_radio *radio = platform_get_drvdata(pdev); - - v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); - video_unregister_device(&radio->videodev); - v4l2_device_unregister(&radio->v4l2dev); - debugfs_remove_recursive(radio->debugfs); - - return 0; -} - -MODULE_ALIAS("platform:si476x-radio"); - -static struct platform_driver si476x_radio_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, - .probe = si476x_radio_probe, - .remove = si476x_radio_remove, -}; -module_platform_driver(si476x_radio_driver); - -MODULE_AUTHOR("Andrey Smirnov "); -MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); -MODULE_LICENSE("GPL"); diff --git a/include/media/si476x.h b/include/media/si476x.h deleted file mode 100644 index beb6433d6958..000000000000 --- a/include/media/si476x.h +++ /dev/null @@ -1,426 +0,0 @@ -/* - * include/media/si476x.h -- Common definitions for si476x driver - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 SI476X_H -#define SI476X_H - -#include -#include - -struct si476x_device; - -/* It is possible to select one of the four adresses using pins A0 - * and A1 on SI476x */ -#define SI476X_I2C_ADDR_1 0x60 -#define SI476X_I2C_ADDR_2 0x61 -#define SI476X_I2C_ADDR_3 0x62 -#define SI476X_I2C_ADDR_4 0x63 - -enum si476x_iqclk_config { - SI476X_IQCLK_NOOP = 0, - SI476X_IQCLK_TRISTATE = 1, - SI476X_IQCLK_IQ = 21, -}; -enum si476x_iqfs_config { - SI476X_IQFS_NOOP = 0, - SI476X_IQFS_TRISTATE = 1, - SI476X_IQFS_IQ = 21, -}; -enum si476x_iout_config { - SI476X_IOUT_NOOP = 0, - SI476X_IOUT_TRISTATE = 1, - SI476X_IOUT_OUTPUT = 22, -}; -enum si476x_qout_config { - SI476X_QOUT_NOOP = 0, - SI476X_QOUT_TRISTATE = 1, - SI476X_QOUT_OUTPUT = 22, -}; - -enum si476x_dclk_config { - SI476X_DCLK_NOOP = 0, - SI476X_DCLK_TRISTATE = 1, - SI476X_DCLK_DAUDIO = 10, -}; - -enum si476x_dfs_config { - SI476X_DFS_NOOP = 0, - SI476X_DFS_TRISTATE = 1, - SI476X_DFS_DAUDIO = 10, -}; - -enum si476x_dout_config { - SI476X_DOUT_NOOP = 0, - SI476X_DOUT_TRISTATE = 1, - SI476X_DOUT_I2S_OUTPUT = 12, - SI476X_DOUT_I2S_INPUT = 13, -}; - -enum si476x_xout_config { - SI476X_XOUT_NOOP = 0, - SI476X_XOUT_TRISTATE = 1, - SI476X_XOUT_I2S_INPUT = 13, - SI476X_XOUT_MODE_SELECT = 23, -}; - - -enum si476x_icin_config { - SI476X_ICIN_NOOP = 0, - SI476X_ICIN_TRISTATE = 1, - SI476X_ICIN_GPO1_HIGH = 2, - SI476X_ICIN_GPO1_LOW = 3, - SI476X_ICIN_IC_LINK = 30, -}; - -enum si476x_icip_config { - SI476X_ICIP_NOOP = 0, - SI476X_ICIP_TRISTATE = 1, - SI476X_ICIP_GPO2_HIGH = 2, - SI476X_ICIP_GPO2_LOW = 3, - SI476X_ICIP_IC_LINK = 30, -}; - -enum si476x_icon_config { - SI476X_ICON_NOOP = 0, - SI476X_ICON_TRISTATE = 1, - SI476X_ICON_I2S = 10, - SI476X_ICON_IC_LINK = 30, -}; - -enum si476x_icop_config { - SI476X_ICOP_NOOP = 0, - SI476X_ICOP_TRISTATE = 1, - SI476X_ICOP_I2S = 10, - SI476X_ICOP_IC_LINK = 30, -}; - - -enum si476x_lrout_config { - SI476X_LROUT_NOOP = 0, - SI476X_LROUT_TRISTATE = 1, - SI476X_LROUT_AUDIO = 2, - SI476X_LROUT_MPX = 3, -}; - - -enum si476x_intb_config { - SI476X_INTB_NOOP = 0, - SI476X_INTB_TRISTATE = 1, - SI476X_INTB_DAUDIO = 10, - SI476X_INTB_IRQ = 40, -}; - -enum si476x_a1_config { - SI476X_A1_NOOP = 0, - SI476X_A1_TRISTATE = 1, - SI476X_A1_IRQ = 40, -}; - -enum si476x_part_revisions { - SI476X_REVISION_A10 = 0, - SI476X_REVISION_A20 = 1, - SI476X_REVISION_A30 = 2, -}; - -struct si476x_pinmux { - enum si476x_dclk_config dclk; - enum si476x_dfs_config dfs; - enum si476x_dout_config dout; - enum si476x_xout_config xout; - - enum si476x_iqclk_config iqclk; - enum si476x_iqfs_config iqfs; - enum si476x_iout_config iout; - enum si476x_qout_config qout; - - enum si476x_icin_config icin; - enum si476x_icip_config icip; - enum si476x_icon_config icon; - enum si476x_icop_config icop; - - enum si476x_lrout_config lrout; - - enum si476x_intb_config intb; - enum si476x_a1_config a1; -}; - -/** - * enum si476x_phase_diversity_mode - possbile phase diversity modes - * for SI4764/5/6/7 chips. - * - * @SI476X_PHDIV_DISABLED: Phase diversity feature is - * disabled. - * @SI476X_PHDIV_PRIMARY_COMBINING: Tuner works as a primary tuner - * in combination with a - * secondary one. - * @SI476X_PHDIV_PRIMARY_ANTENNA: Tuner works as a primary tuner - * using only its own antenna. - * @SI476X_PHDIV_SECONDARY_ANTENNA: Tuner works as a primary tuner - * usning seconary tuner's antenna. - * @SI476X_PHDIV_SECONDARY_COMBINING: Tuner works as a secondary - * tuner in combination with the - * primary one. - */ -enum si476x_phase_diversity_mode { - SI476X_PHDIV_DISABLED = 0, - SI476X_PHDIV_PRIMARY_COMBINING = 1, - SI476X_PHDIV_PRIMARY_ANTENNA = 2, - SI476X_PHDIV_SECONDARY_ANTENNA = 3, - SI476X_PHDIV_SECONDARY_COMBINING = 5, -}; - -enum si476x_ibias6x { - SI476X_IBIAS6X_OTHER = 0, - SI476X_IBIAS6X_RCVR1_NON_4MHZ_CLK = 1, -}; - -enum si476x_xstart { - SI476X_XSTART_MULTIPLE_TUNER = 0x11, - SI476X_XSTART_NORMAL = 0x77, -}; - -enum si476x_freq { - SI476X_FREQ_4_MHZ = 0, - SI476X_FREQ_37P209375_MHZ = 1, - SI476X_FREQ_36P4_MHZ = 2, - SI476X_FREQ_37P8_MHZ = 3, -}; - -enum si476x_xmode { - SI476X_XMODE_CRYSTAL_RCVR1 = 1, - SI476X_XMODE_EXT_CLOCK = 2, - SI476X_XMODE_CRYSTAL_RCVR2_3 = 3, -}; - -enum si476x_xbiashc { - SI476X_XBIASHC_SINGLE_RECEIVER = 0, - SI476X_XBIASHC_MULTIPLE_RECEIVER = 1, -}; - -enum si476x_xbias { - SI476X_XBIAS_RCVR2_3 = 0, - SI476X_XBIAS_4MHZ_RCVR1 = 3, - SI476X_XBIAS_RCVR1 = 7, -}; - -enum si476x_func { - SI476X_FUNC_BOOTLOADER = 0, - SI476X_FUNC_FM_RECEIVER = 1, - SI476X_FUNC_AM_RECEIVER = 2, - SI476X_FUNC_WB_RECEIVER = 3, -}; - - -/** - * @xcload: Selects the amount of additional on-chip capacitance to - * be connected between XTAL1 and gnd and between XTAL2 and - * GND. One half of the capacitance value shown here is the - * additional load capacitance presented to the xtal. The - * minimum step size is 0.277 pF. Recommended value is 0x28 - * but it will be layout dependent. Range is 0–0x3F i.e. - * (0–16.33 pF) - * @ctsien: enable CTSINT(interrupt request when CTS condition - * arises) when set - * @intsel: when set A1 pin becomes the interrupt pin; otherwise, - * INTB is the interrupt pin - * @func: selects the boot function of the device. I.e. - * SI476X_BOOTLOADER - Boot loader - * SI476X_FM_RECEIVER - FM receiver - * SI476X_AM_RECEIVER - AM receiver - * SI476X_WB_RECEIVER - Weatherband receiver - * @freq: oscillator's crystal frequency: - * SI476X_XTAL_37P209375_MHZ - 37.209375 Mhz - * SI476X_XTAL_36P4_MHZ - 36.4 Mhz - * SI476X_XTAL_37P8_MHZ - 37.8 Mhz - */ -struct si476x_power_up_args { - enum si476x_ibias6x ibias6x; - enum si476x_xstart xstart; - u8 xcload; - bool fastboot; - enum si476x_xbiashc xbiashc; - enum si476x_xbias xbias; - enum si476x_func func; - enum si476x_freq freq; - enum si476x_xmode xmode; -}; - - -enum si476x_ctrl_id { - V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1), - V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2), - V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3), - V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4), - V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5), - V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6), -}; - -/* - * Platform dependent definition - */ -struct si476x_platform_data { - int gpio_reset; /* < 0 if not used */ - - struct si476x_power_up_args power_up_parameters; - enum si476x_phase_diversity_mode diversity_mode; - - struct si476x_pinmux pinmux; -}; - -/** - * struct si476x_rsq_status - structure containing received signal - * quality - * @multhint: Multipath Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD - * @multlint: Multipath Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_MULTIPATH_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_MULTIPATH_LOW_THRESHOLD - * @snrhint: SNR Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_SNR_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_SNR_HIGH_THRESHOLD - * @snrlint: SNR Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_SNR_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_SNR_LOW_THRESHOLD - * @rssihint: RSSI Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_RSSI_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_RSSI_HIGH_THRESHOLD - * @rssilint: RSSI Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_RSSI_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_RSSI_LOW_THRESHOLD - * @bltf: Band Limit. - * Set if seek command hits the band limit or wrapped to - * the original frequency. - * @snr_ready: SNR measurement in progress. - * @rssiready: RSSI measurement in progress. - * @afcrl: Set if FREQOFF >= MAX_TUNE_ERROR - * @valid: Set if the channel is valid - * rssi < FM_VALID_RSSI_THRESHOLD - * snr < FM_VALID_SNR_THRESHOLD - * tune_error < FM_VALID_MAX_TUNE_ERROR - * @readfreq: Current tuned frequency. - * @freqoff: Signed frequency offset. - * @rssi: Received Signal Strength Indicator(dBuV). - * @snr: RF SNR Indicator(dB). - * @lassi: - * @hassi: Low/High side Adjacent(100 kHz) Channel Strength Indicator - * @mult: Multipath indicator - * @dev: Who knows? But values may vary. - * @readantcap: Antenna tuning capacity value. - * @assi: Adjacent Channel(+/- 200kHz) Strength Indicator - * @usn: Ultrasonic Noise Inticator in -DBFS - */ -struct si476x_rsq_status_report { - __u8 multhint, multlint; - __u8 snrhint, snrlint; - __u8 rssihint, rssilint; - __u8 bltf; - __u8 snr_ready; - __u8 rssiready; - __u8 injside; - __u8 afcrl; - __u8 valid; - - __u16 readfreq; - __s8 freqoff; - __s8 rssi; - __s8 snr; - __s8 issi; - __s8 lassi, hassi; - __s8 mult; - __u8 dev; - __u16 readantcap; - __s8 assi; - __s8 usn; - - __u8 pilotdev; - __u8 rdsdev; - __u8 assidev; - __u8 strongdev; - __u16 rdspi; -} __packed; - -/** - * si476x_acf_status_report - ACF report results - * - * @blend_int: If set, indicates that stereo separation has crossed - * below the blend threshold as set by FM_ACF_BLEND_THRESHOLD - * @hblend_int: If set, indicates that HiBlend cutoff frequency is - * lower than threshold as set by FM_ACF_HBLEND_THRESHOLD - * @hicut_int: If set, indicates that HiCut cutoff frequency is lower - * than the threshold set by ACF_ - - */ -struct si476x_acf_status_report { - __u8 blend_int; - __u8 hblend_int; - __u8 hicut_int; - __u8 chbw_int; - __u8 softmute_int; - __u8 smute; - __u8 smattn; - __u8 chbw; - __u8 hicut; - __u8 hiblend; - __u8 pilot; - __u8 stblend; -} __packed; - -enum si476x_fmagc { - SI476X_FMAGC_10K_OHM = 0, - SI476X_FMAGC_800_OHM = 1, - SI476X_FMAGC_400_OHM = 2, - SI476X_FMAGC_200_OHM = 4, - SI476X_FMAGC_100_OHM = 8, - SI476X_FMAGC_50_OHM = 16, - SI476X_FMAGC_25_OHM = 32, - SI476X_FMAGC_12P5_OHM = 64, - SI476X_FMAGC_6P25_OHM = 128, -}; - -struct si476x_agc_status_report { - __u8 mxhi; - __u8 mxlo; - __u8 lnahi; - __u8 lnalo; - __u8 fmagc1; - __u8 fmagc2; - __u8 pgagain; - __u8 fmwblang; -} __packed; - -struct si476x_rds_blockcount_report { - __u16 expected; - __u16 received; - __u16 uncorrectable; -} __packed; - -#endif /* SI476X_H*/ -- cgit v1.2.3 From 33a31edd4a4b7d26b962b32decfd8ea2377eaa0d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 17 Apr 2013 06:07:01 -0300 Subject: Revert "[media] mfd: Add header files and Kbuild plumbing for SI476x MFD core" As requested by Samuel Ortiz , revert this patch. This reverts commit 3f8ec5df11aa2ad7402cfb3368532a96b63426a4. Conflicts: drivers/mfd/Kconfig Signed-off-by: Mauro Carvalho Chehab --- drivers/mfd/Kconfig | 13 - drivers/mfd/Makefile | 4 - include/linux/mfd/si476x-core.h | 525 ---------------------------------------- 3 files changed, 542 deletions(-) delete mode 100644 include/linux/mfd/si476x-core.h (limited to 'include') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b6bb6d5f89e7..c346941a2515 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -977,19 +977,6 @@ config MFD_WL1273_CORE driver connects the radio-wl1273 V4L2 module and the wl1273 audio codec. -config MFD_SI476X_CORE - tristate "Support for Silicon Laboratories 4761/64/68 AM/FM radio." - depends on I2C - select MFD_CORE - select REGMAP_I2C - help - This is the core driver for the SI476x series of AM/FM - radio. This MFD driver connects the radio-si476x V4L2 module - and the si476x audio codec. - - To compile this driver as a module, choose M here: the - module will be called si476x-core. - config MFD_OMAP_USB_HOST bool "Support OMAP USBHS core and TLL driver" depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b7aaa1e104a1..b90409c23664 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -131,10 +131,6 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o - -si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o -obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o - obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o diff --git a/include/linux/mfd/si476x-core.h b/include/linux/mfd/si476x-core.h deleted file mode 100644 index 2136b2631dc3..000000000000 --- a/include/linux/mfd/si476x-core.h +++ /dev/null @@ -1,525 +0,0 @@ -/* - * include/media/si476x-core.h -- Common definitions for si476x core - * device - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * - * Author: Andrey Smirnov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 SI476X_CORE_H -#define SI476X_CORE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Command Timeouts */ -#define SI476X_DEFAULT_TIMEOUT 100000 -#define SI476X_TIMEOUT_TUNE 700000 -#define SI476X_TIMEOUT_POWER_UP 330000 -#define SI476X_STATUS_POLL_US 0 - -/* -------------------- si476x-i2c.c ----------------------- */ - -enum si476x_freq_supported_chips { - SI476X_CHIP_SI4761 = 1, - SI476X_CHIP_SI4764, - SI476X_CHIP_SI4768, -}; - -enum si476x_mfd_cells { - SI476X_RADIO_CELL = 0, - SI476X_CODEC_CELL, - SI476X_MFD_CELLS, -}; - -/** - * enum si476x_power_state - possible power state of the si476x - * device. - * - * @SI476X_POWER_DOWN: In this state all regulators are turned off - * and the reset line is pulled low. The device is completely - * inactive. - * @SI476X_POWER_UP_FULL: In this state all the power regualtors are - * turned on, reset line pulled high, IRQ line is enabled(polling is - * active for polling use scenario) and device is turned on with - * POWER_UP command. The device is ready to be used. - * @SI476X_POWER_INCONSISTENT: This state indicates that previous - * power down was inconsistent, meaning some of the regulators were - * not turned down and thus use of the device, without power-cycling - * is impossible. - */ -enum si476x_power_state { - SI476X_POWER_DOWN = 0, - SI476X_POWER_UP_FULL = 1, - SI476X_POWER_INCONSISTENT = 2, -}; - -/** - * struct si476x_core - internal data structure representing the - * underlying "core" device which all the MFD cell-devices use. - * - * @client: Actual I2C client used to transfer commands to the chip. - * @chip_id: Last digit of the chip model(E.g. "1" for SI4761) - * @cells: MFD cell devices created by this driver. - * @cmd_lock: Mutex used to serialize all the requests to the core - * device. This filed should not be used directly. Instead - * si476x_core_lock()/si476x_core_unlock() should be used to get - * exclusive access to the "core" device. - * @users: Active users counter(Used by the radio cell) - * @rds_read_queue: Wait queue used to wait for RDS data. - * @rds_fifo: FIFO in which all the RDS data received from the chip is - * placed. - * @rds_fifo_drainer: Worker that drains on-chip RDS FIFO. - * @rds_drainer_is_working: Flag used for launching only one instance - * of the @rds_fifo_drainer. - * @rds_drainer_status_lock: Lock used to guard access to the - * @rds_drainer_is_working variable. - * @command: Wait queue for wainting on the command comapletion. - * @cts: Clear To Send flag set upon receiving first status with CTS - * set. - * @tuning: Wait queue used for wainting for tune/seek comand - * completion. - * @stc: Similar to @cts, but for the STC bit of the status value. - * @power_up_parameters: Parameters used as argument for POWER_UP - * command when the device is started. - * @state: Current power state of the device. - * @supplues: Structure containing handles to all power supplies used - * by the device (NULL ones are ignored). - * @gpio_reset: GPIO pin connectet to the RSTB pin of the chip. - * @pinmux: Chip's configurable pins configuration. - * @diversity_mode: Chips role when functioning in diversity mode. - * @status_monitor: Polling worker used in polling use case scenarion - * (when IRQ is not avalible). - * @revision: Chip's running firmware revision number(Used for correct - * command set support). - */ - -struct si476x_core { - struct i2c_client *client; - struct regmap *regmap; - int chip_id; - struct mfd_cell cells[SI476X_MFD_CELLS]; - - struct mutex cmd_lock; /* for serializing fm radio operations */ - atomic_t users; - - wait_queue_head_t rds_read_queue; - struct kfifo rds_fifo; - struct work_struct rds_fifo_drainer; - bool rds_drainer_is_working; - struct mutex rds_drainer_status_lock; - - wait_queue_head_t command; - atomic_t cts; - - wait_queue_head_t tuning; - atomic_t stc; - - struct si476x_power_up_args power_up_parameters; - - enum si476x_power_state power_state; - - struct regulator_bulk_data supplies[4]; - - int gpio_reset; - - struct si476x_pinmux pinmux; - enum si476x_phase_diversity_mode diversity_mode; - - atomic_t is_alive; - - struct delayed_work status_monitor; -#define SI476X_WORK_TO_CORE(w) container_of(to_delayed_work(w), \ - struct si476x_core, \ - status_monitor) - - int revision; - - int rds_fifo_depth; -}; - -static inline struct si476x_core *i2c_mfd_cell_to_core(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev->parent); - return i2c_get_clientdata(client); -} - - -/** - * si476x_core_lock() - lock the core device to get an exclusive access - * to it. - */ -static inline void si476x_core_lock(struct si476x_core *core) -{ - mutex_lock(&core->cmd_lock); -} - -/** - * si476x_core_unlock() - unlock the core device to relinquish an - * exclusive access to it. - */ -static inline void si476x_core_unlock(struct si476x_core *core) -{ - mutex_unlock(&core->cmd_lock); -} - -/* *_TUNE_FREQ family of commands accept frequency in multiples of - 10kHz */ -static inline u16 hz_to_si476x(struct si476x_core *core, int freq) -{ - u16 result; - - switch (core->power_up_parameters.func) { - default: - case SI476X_FUNC_FM_RECEIVER: - result = freq / 10000; - break; - case SI476X_FUNC_AM_RECEIVER: - result = freq / 1000; - break; - } - - return result; -} - -static inline int si476x_to_hz(struct si476x_core *core, u16 freq) -{ - int result; - - switch (core->power_up_parameters.func) { - default: - case SI476X_FUNC_FM_RECEIVER: - result = freq * 10000; - break; - case SI476X_FUNC_AM_RECEIVER: - result = freq * 1000; - break; - } - - return result; -} - -/* Since the V4L2_TUNER_CAP_LOW flag is supplied, V4L2 subsystem - * mesures frequency in 62.5 Hz units */ - -static inline int hz_to_v4l2(int freq) -{ - return (freq * 10) / 625; -} - -static inline int v4l2_to_hz(int freq) -{ - return (freq * 625) / 10; -} - -static inline u16 v4l2_to_si476x(struct si476x_core *core, int freq) -{ - return hz_to_si476x(core, v4l2_to_hz(freq)); -} - -static inline int si476x_to_v4l2(struct si476x_core *core, u16 freq) -{ - return hz_to_v4l2(si476x_to_hz(core, freq)); -} - - - -/** - * struct si476x_func_info - structure containing result of the - * FUNC_INFO command. - * - * @firmware.major: Firmware major number. - * @firmware.minor[...]: Firmware minor numbers. - * @patch_id: - * @func: Mode tuner is working in. - */ -struct si476x_func_info { - struct { - u8 major, minor[2]; - } firmware; - u16 patch_id; - enum si476x_func func; -}; - -/** - * struct si476x_power_down_args - structure used to pass parameters - * to POWER_DOWN command - * - * @xosc: true - Power down, but leav oscillator running. - * false - Full power down. - */ -struct si476x_power_down_args { - bool xosc; -}; - -/** - * enum si476x_tunemode - enum representing possible tune modes for - * the chip. - * @SI476X_TM_VALIDATED_NORMAL_TUNE: Unconditionally stay on the new - * channel after tune, tune status is valid. - * @SI476X_TM_INVALIDATED_FAST_TUNE: Unconditionally stay in the new - * channel after tune, tune status invalid. - * @SI476X_TM_VALIDATED_AF_TUNE: Jump back to previous channel if - * metric thresholds are not met. - * @SI476X_TM_VALIDATED_AF_CHECK: Unconditionally jump back to the - * previous channel. - */ -enum si476x_tunemode { - SI476X_TM_VALIDATED_NORMAL_TUNE = 0, - SI476X_TM_INVALIDATED_FAST_TUNE = 1, - SI476X_TM_VALIDATED_AF_TUNE = 2, - SI476X_TM_VALIDATED_AF_CHECK = 3, -}; - -/** - * enum si476x_smoothmetrics - enum containing the possible setting fo - * audio transitioning of the chip - * @SI476X_SM_INITIALIZE_AUDIO: Initialize audio state to match this - * new channel - * @SI476X_SM_TRANSITION_AUDIO: Transition audio state from previous - * channel values to the new values - */ -enum si476x_smoothmetrics { - SI476X_SM_INITIALIZE_AUDIO = 0, - SI476X_SM_TRANSITION_AUDIO = 1, -}; - -/** - * struct si476x_rds_status_report - the structure representing the - * response to 'FM_RD_STATUS' command - * @rdstpptyint: Traffic program flag(TP) and/or program type(PTY) - * code has changed. - * @rdspiint: Program indentifiaction(PI) code has changed. - * @rdssyncint: RDS synchronization has changed. - * @rdsfifoint: RDS was received and the RDS FIFO has at least - * 'FM_RDS_INTERRUPT_FIFO_COUNT' elements in it. - * @tpptyvalid: TP flag and PTY code are valid falg. - * @pivalid: PI code is valid flag. - * @rdssync: RDS is currently synchronized. - * @rdsfifolost: On or more RDS groups have been lost/discarded flag. - * @tp: Current channel's TP flag. - * @pty: Current channel's PTY code. - * @pi: Current channel's PI code. - * @rdsfifoused: Number of blocks remaining in the RDS FIFO (0 if - * empty). - */ -struct si476x_rds_status_report { - bool rdstpptyint, rdspiint, rdssyncint, rdsfifoint; - bool tpptyvalid, pivalid, rdssync, rdsfifolost; - bool tp; - - u8 pty; - u16 pi; - - u8 rdsfifoused; - u8 ble[4]; - - struct v4l2_rds_data rds[4]; -}; - -struct si476x_rsq_status_args { - bool primary; - bool rsqack; - bool attune; - bool cancel; - bool stcack; -}; - -enum si476x_injside { - SI476X_INJSIDE_AUTO = 0, - SI476X_INJSIDE_LOW = 1, - SI476X_INJSIDE_HIGH = 2, -}; - -struct si476x_tune_freq_args { - bool zifsr; - bool hd; - enum si476x_injside injside; - int freq; - enum si476x_tunemode tunemode; - enum si476x_smoothmetrics smoothmetrics; - int antcap; -}; - -int si476x_core_stop(struct si476x_core *, bool); -int si476x_core_start(struct si476x_core *, bool); -int si476x_core_set_power_state(struct si476x_core *, enum si476x_power_state); -bool si476x_core_has_am(struct si476x_core *); -bool si476x_core_has_diversity(struct si476x_core *); -bool si476x_core_is_a_secondary_tuner(struct si476x_core *); -bool si476x_core_is_a_primary_tuner(struct si476x_core *); -bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core); -bool si476x_core_is_powered_up(struct si476x_core *core); - -enum si476x_i2c_type { - SI476X_I2C_SEND, - SI476X_I2C_RECV -}; - -int si476x_core_i2c_xfer(struct si476x_core *, - enum si476x_i2c_type, - char *, int); - - -/* -------------------- si476x-cmd.c ----------------------- */ - -int si476x_core_cmd_func_info(struct si476x_core *, struct si476x_func_info *); -int si476x_core_cmd_set_property(struct si476x_core *, u16, u16); -int si476x_core_cmd_get_property(struct si476x_core *, u16); -int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *, - enum si476x_dclk_config, - enum si476x_dfs_config, - enum si476x_dout_config, - enum si476x_xout_config); -int si476x_core_cmd_zif_pin_cfg(struct si476x_core *, - enum si476x_iqclk_config, - enum si476x_iqfs_config, - enum si476x_iout_config, - enum si476x_qout_config); -int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *, - enum si476x_icin_config, - enum si476x_icip_config, - enum si476x_icon_config, - enum si476x_icop_config); -int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *, - enum si476x_lrout_config); -int si476x_core_cmd_intb_pin_cfg(struct si476x_core *, enum si476x_intb_config, - enum si476x_a1_config); -int si476x_core_cmd_fm_seek_start(struct si476x_core *, bool, bool); -int si476x_core_cmd_am_seek_start(struct si476x_core *, bool, bool); -int si476x_core_cmd_fm_rds_status(struct si476x_core *, bool, bool, bool, - struct si476x_rds_status_report *); -int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *, bool, - struct si476x_rds_blockcount_report *); -int si476x_core_cmd_fm_tune_freq(struct si476x_core *, - struct si476x_tune_freq_args *); -int si476x_core_cmd_am_tune_freq(struct si476x_core *, - struct si476x_tune_freq_args *); -int si476x_core_cmd_am_rsq_status(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); -int si476x_core_cmd_fm_rsq_status(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); -int si476x_core_cmd_power_up(struct si476x_core *, - struct si476x_power_up_args *); -int si476x_core_cmd_power_down(struct si476x_core *, - struct si476x_power_down_args *); -int si476x_core_cmd_fm_phase_div_status(struct si476x_core *); -int si476x_core_cmd_fm_phase_diversity(struct si476x_core *, - enum si476x_phase_diversity_mode); - -int si476x_core_cmd_fm_acf_status(struct si476x_core *, - struct si476x_acf_status_report *); -int si476x_core_cmd_am_acf_status(struct si476x_core *, - struct si476x_acf_status_report *); -int si476x_core_cmd_agc_status(struct si476x_core *, - struct si476x_agc_status_report *); - -enum si476x_power_grid_type { - SI476X_POWER_GRID_50HZ = 0, - SI476X_POWER_GRID_60HZ, -}; - -/* Properties */ - -enum si476x_interrupt_flags { - SI476X_STCIEN = (1 << 0), - SI476X_ACFIEN = (1 << 1), - SI476X_RDSIEN = (1 << 2), - SI476X_RSQIEN = (1 << 3), - - SI476X_ERRIEN = (1 << 6), - SI476X_CTSIEN = (1 << 7), - - SI476X_STCREP = (1 << 8), - SI476X_ACFREP = (1 << 9), - SI476X_RDSREP = (1 << 10), - SI476X_RSQREP = (1 << 11), -}; - -enum si476x_rdsint_sources { - SI476X_RDSTPPTY = (1 << 4), - SI476X_RDSPI = (1 << 3), - SI476X_RDSSYNC = (1 << 1), - SI476X_RDSRECV = (1 << 0), -}; - -enum si476x_status_response_bits { - SI476X_CTS = (1 << 7), - SI476X_ERR = (1 << 6), - /* Status response for WB receiver */ - SI476X_WB_ASQ_INT = (1 << 4), - SI476X_RSQ_INT = (1 << 3), - /* Status response for FM receiver */ - SI476X_FM_RDS_INT = (1 << 2), - SI476X_ACF_INT = (1 << 1), - SI476X_STC_INT = (1 << 0), -}; - -/* -------------------- si476x-prop.c ----------------------- */ - -enum si476x_common_receiver_properties { - SI476X_PROP_INT_CTL_ENABLE = 0x0000, - SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE = 0x0200, - SI476X_PROP_DIGITAL_IO_INPUT_FORMAT = 0x0201, - SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, - SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, - - SI476X_PROP_SEEK_BAND_BOTTOM = 0x1100, - SI476X_PROP_SEEK_BAND_TOP = 0x1101, - SI476X_PROP_SEEK_FREQUENCY_SPACING = 0x1102, - - SI476X_PROP_VALID_MAX_TUNE_ERROR = 0x2000, - SI476X_PROP_VALID_SNR_THRESHOLD = 0x2003, - SI476X_PROP_VALID_RSSI_THRESHOLD = 0x2004, -}; - -enum si476x_am_receiver_properties { - SI476X_PROP_AUDIO_PWR_LINE_FILTER = 0x0303, -}; - -enum si476x_fm_receiver_properties { - SI476X_PROP_AUDIO_DEEMPHASIS = 0x0302, - - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE = 0x4000, - SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT = 0x4001, - SI476X_PROP_FM_RDS_CONFIG = 0x4002, -}; - -enum si476x_prop_audio_pwr_line_filter_bits { - SI476X_PROP_PWR_HARMONICS_MASK = 0b0000000000011111, - SI476X_PROP_PWR_GRID_MASK = 0b0000000100000000, - SI476X_PROP_PWR_ENABLE_MASK = 0b0000001000000000, - SI476X_PROP_PWR_GRID_50HZ = 0b0000000000000000, - SI476X_PROP_PWR_GRID_60HZ = 0b0000000100000000, -}; - -enum si476x_prop_fm_rds_config_bits { - SI476X_PROP_RDSEN_MASK = 0x1, - SI476X_PROP_RDSEN = 0x1, -}; - - -struct regmap *devm_regmap_init_si476x(struct si476x_core *); - -#endif /* SI476X_CORE_H */ -- cgit v1.2.3 From b879a9c2a755d4ddf9e685258de6435710fd2f03 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 18 Apr 2013 20:46:08 -0300 Subject: [media] v4l2: Add a V4L2 driver for SI476X MFD This commit adds a driver that exposes all the radio related functionality of the Si476x series of chips via the V4L2 subsystem. [mchehab@redhat.com: change it to depends on MFD_SI476X_CORE instead of selecting it; vidioc_s_register now uses const struct] Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/si476x.txt | 187 ++++ drivers/media/radio/Kconfig | 16 + drivers/media/radio/Makefile | 1 + drivers/media/radio/radio-si476x.c | 1599 ++++++++++++++++++++++++++++++++++ include/media/si476x.h | 37 + 5 files changed, 1840 insertions(+) create mode 100644 Documentation/video4linux/si476x.txt create mode 100644 drivers/media/radio/radio-si476x.c create mode 100644 include/media/si476x.h (limited to 'include') diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt new file mode 100644 index 000000000000..d1a08db2cbd9 --- /dev/null +++ b/Documentation/video4linux/si476x.txt @@ -0,0 +1,187 @@ +SI476x Driver Readme +------------------------------------------------ + Copyright (C) 2013 Andrey Smirnov + +TODO for the driver +------------------------------ + +- According to the SiLabs' datasheet it is possible to update the + firmware of the radio chip in the run-time, thus bringing it to the + most recent version. Unfortunately I couldn't find any mentioning of + the said firmware update for the old chips that I tested the driver + against, so for chips like that the driver only exposes the old + functionality. + + +Parameters exposed over debugfs +------------------------------- +SI476x allow user to get multiple characteristics that can be very +useful for EoL testing/RF performance estimation, parameters that have +very little to do with V4L2 subsystem. Such parameters are exposed via +debugfs and can be accessed via regular file I/O operations. + +The drivers exposes following files: + +* /sys/kernel/debug//acf + This file contains ACF(Automatically Controlled Features) status + information. The contents of the file is binary data of the + following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | blend_int | Flag, set when stereo separation has + | | crossed below the blend threshold + -------------------------------------------------------------------- + 0x01 | hblend_int | Flag, set when HiBlend cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x02 | hicut_int | Flag, set when HiCut cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x03 | chbw_int | Flag, set when channel filter + | | bandwidth is less than threshold + -------------------------------------------------------------------- + 0x04 | softmute_int | Flag indicating that softmute + | | attenuation has increased above + | | softmute threshold + -------------------------------------------------------------------- + 0x05 | smute | 0 - Audio is not soft muted + | | 1 - Audio is soft muted + -------------------------------------------------------------------- + 0x06 | smattn | Soft mute attenuation level in dB + -------------------------------------------------------------------- + 0x07 | chbw | Channel filter bandwidth in kHz + -------------------------------------------------------------------- + 0x08 | hicut | HiCut cutoff frequency in units of + | | 100Hz + -------------------------------------------------------------------- + 0x09 | hiblend | HiBlend cutoff frequency in units + | | of 100 Hz + -------------------------------------------------------------------- + 0x10 | pilot | 0 - Stereo pilot is not present + | | 1 - Stereo pilot is present + -------------------------------------------------------------------- + 0x11 | stblend | Stereo blend in % + -------------------------------------------------------------------- + + +* /sys/kernel/debug//rds_blckcnt + This file contains statistics about RDS receptions. It's binary data + has the following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | expected | Number of expected RDS blocks + -------------------------------------------------------------------- + 0x02 | received | Number of received RDS blocks + -------------------------------------------------------------------- + 0x04 | uncorrectable | Number of uncorrectable RDS blocks + -------------------------------------------------------------------- + +* /sys/kernel/debug//agc + This file contains information about parameters pertaining to + AGC(Automatic Gain Control) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | mxhi | 0 - FM Mixer PD high threshold is + | | not tripped + | | 1 - FM Mixer PD high threshold is + | | tripped + -------------------------------------------------------------------- + 0x01 | mxlo | ditto for FM Mixer PD low + -------------------------------------------------------------------- + 0x02 | lnahi | ditto for FM LNA PD high + -------------------------------------------------------------------- + 0x03 | lnalo | ditto for FM LNA PD low + -------------------------------------------------------------------- + 0x04 | fmagc1 | FMAGC1 attenuator resistance + | | (see datasheet for more detail) + -------------------------------------------------------------------- + 0x05 | fmagc2 | ditto for FMAGC2 + -------------------------------------------------------------------- + 0x06 | pgagain | PGA gain in dB + -------------------------------------------------------------------- + 0x07 | fmwblang | FM/WB LNA Gain in dB + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | multhint | 0 - multipath value has not crossed + | | the Multipath high threshold + | | 1 - multipath value has crossed + | | the Multipath high threshold + -------------------------------------------------------------------- + 0x01 | multlint | ditto for Multipath low threshold + -------------------------------------------------------------------- + 0x02 | snrhint | 0 - received signal's SNR has not + | | crossed high threshold + | | 1 - received signal's SNR has + | | crossed high threshold + -------------------------------------------------------------------- + 0x03 | snrlint | ditto for low threshold + -------------------------------------------------------------------- + 0x04 | rssihint | ditto for RSSI high threshold + -------------------------------------------------------------------- + 0x05 | rssilint | ditto for RSSI low threshold + -------------------------------------------------------------------- + 0x06 | bltf | Flag indicating if seek command + | | reached/wrapped seek band limit + -------------------------------------------------------------------- + 0x07 | snr_ready | Indicates that SNR metrics is ready + -------------------------------------------------------------------- + 0x08 | rssiready | ditto for RSSI metrics + -------------------------------------------------------------------- + 0x09 | injside | 0 - Low-side injection is being used + | | 1 - High-side injection is used + -------------------------------------------------------------------- + 0x10 | afcrl | Flag indicating if AFC rails + -------------------------------------------------------------------- + 0x11 | valid | Flag indicating if channel is valid + -------------------------------------------------------------------- + 0x12 | readfreq | Current tuned frequency + -------------------------------------------------------------------- + 0x14 | freqoff | Singed frequency offset in units of + | | 2ppm + -------------------------------------------------------------------- + 0x15 | rssi | Signed value of RSSI in dBuV + -------------------------------------------------------------------- + 0x16 | snr | Signed RF SNR in dB + -------------------------------------------------------------------- + 0x17 | issi | Signed Image Strength Signal + | | indicator + -------------------------------------------------------------------- + 0x18 | lassi | Signed Low side adjacent Channel + | | Strength indicator + -------------------------------------------------------------------- + 0x19 | hassi | ditto fpr High side + -------------------------------------------------------------------- + 0x20 | mult | Multipath indicator + -------------------------------------------------------------------- + 0x21 | dev | Frequency deviation + -------------------------------------------------------------------- + 0x24 | assi | Adjascent channel SSI + -------------------------------------------------------------------- + 0x25 | usn | Ultrasonic noise indicator + -------------------------------------------------------------------- + 0x26 | pilotdev | Pilot deviation in units of 100 Hz + -------------------------------------------------------------------- + 0x27 | rdsdev | ditto for RDS + -------------------------------------------------------------------- + 0x28 | assidev | ditto for ASSI + -------------------------------------------------------------------- + 0x29 | strongdev | Frequency deviation + -------------------------------------------------------------------- + 0x30 | rdspi | RDS PI code + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq_primary + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) for primary tuner only. Layout is as + the one above. diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 24e64a09884c..c0beee2fa37c 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -18,6 +18,22 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" +config RADIO_SI476X + tristate "Silicon Laboratories Si476x I2C FM Radio" + depends on I2C && VIDEO_V4L2 + depends on MFD_SI476X_CORE + select SND_SOC_SI476X + ---help--- + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-si476x. + config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 303eaebdb85a..0dcdb320cfc7 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o +obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c new file mode 100644 index 000000000000..9430c6a29937 --- /dev/null +++ b/drivers/media/radio/radio-si476x.c @@ -0,0 +1,1599 @@ +/* + * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define FM_FREQ_RANGE_LOW 64000000 +#define FM_FREQ_RANGE_HIGH 108000000 + +#define AM_FREQ_RANGE_LOW 520000 +#define AM_FREQ_RANGE_HIGH 30000000 + +#define PWRLINEFLTR (1 << 8) + +#define FREQ_MUL (10000000 / 625) + +#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) + +#define DRIVER_NAME "si476x-radio" +#define DRIVER_CARD "SI476x AM/FM Receiver" + +enum si476x_freq_bands { + SI476X_BAND_FM, + SI476X_BAND_AM, +}; + +static const struct v4l2_frequency_band si476x_bands[] = { + [SI476X_BAND_FM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_FM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 64 * FREQ_MUL, + .rangehigh = 108 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_FM, + }, + [SI476X_BAND_AM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_AM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 0.52 * FREQ_MUL, + .rangehigh = 30 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_AM, + }, +}; + +static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band) +{ + return freq >= si476x_bands[band].rangelow && + freq <= si476x_bands[band].rangehigh; +} + +static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high, + int band) +{ + return low >= si476x_bands[band].rangelow && + high <= si476x_bands[band].rangehigh; +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl); +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl); + +enum phase_diversity_modes_idx { + SI476X_IDX_PHDIV_DISABLED, + SI476X_IDX_PHDIV_PRIMARY_COMBINING, + SI476X_IDX_PHDIV_PRIMARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_COMBINING, +}; + +static const char * const phase_diversity_modes[] = { + [SI476X_IDX_PHDIV_DISABLED] = "Disabled", + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary", + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary", +}; + +static inline enum phase_diversity_modes_idx +si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode) +{ + switch (mode) { + default: /* FALLTHROUGH */ + case SI476X_PHDIV_DISABLED: + return SI476X_IDX_PHDIV_DISABLED; + case SI476X_PHDIV_PRIMARY_COMBINING: + return SI476X_IDX_PHDIV_PRIMARY_COMBINING; + case SI476X_PHDIV_PRIMARY_ANTENNA: + return SI476X_IDX_PHDIV_PRIMARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_ANTENNA: + return SI476X_IDX_PHDIV_SECONDARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_COMBINING: + return SI476X_IDX_PHDIV_SECONDARY_COMBINING; + } +} + +static inline enum si476x_phase_diversity_mode +si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx) +{ + static const int idx_to_value[] = { + [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED, + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING, + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING, + }; + + return idx_to_value[idx]; +} + +static const struct v4l2_ctrl_ops si476x_ctrl_ops = { + .g_volatile_ctrl = si476x_radio_g_volatile_ctrl, + .s_ctrl = si476x_radio_s_ctrl, +}; + + +enum si476x_ctrl_idx { + SI476X_IDX_RSSI_THRESHOLD, + SI476X_IDX_SNR_THRESHOLD, + SI476X_IDX_MAX_TUNE_ERROR, + SI476X_IDX_HARMONICS_COUNT, + SI476X_IDX_DIVERSITY_MODE, + SI476X_IDX_INTERCHIP_LINK, +}; +static struct v4l2_ctrl_config si476x_ctrls[] = { + + /** + * SI476X during its station seeking(or tuning) process uses several + * parameters to detrmine if "the station" is valid: + * + * - Signal's SNR(in dBuV) must be lower than + * #V4L2_CID_SI476X_SNR_THRESHOLD + * - Signal's RSSI(in dBuV) must be greater than + * #V4L2_CID_SI476X_RSSI_THRESHOLD + * - Signal's frequency deviation(in units of 2ppm) must not be + * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR + */ + [SI476X_IDX_RSSI_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_RSSI_THRESHOLD, + .name = "Valid RSSI Threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_SNR_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_SNR_THRESHOLD, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Valid SNR Threshold", + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_MAX_TUNE_ERROR] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_MAX_TUNE_ERROR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Max Tune Errors", + .min = 0, + .max = 126 * 2, + .step = 2, + }, + + /** + * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics + * built-in power-line noise supression filter is to reject + * during AM-mode operation. + */ + [SI476X_IDX_HARMONICS_COUNT] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_HARMONICS_COUNT, + .type = V4L2_CTRL_TYPE_INTEGER, + + .name = "Count of Harmonics to Reject", + .min = 0, + .max = 20, + .step = 1, + }, + + /** + * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which + * two tuners working in diversity mode are to work in. + * + * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled + * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is + * on, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is + * off, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is + * off, secondary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is + * on, secondary tuner's antenna is the main one. + */ + [SI476X_IDX_DIVERSITY_MODE] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_DIVERSITY_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Phase Diversity Mode", + .qmenu = phase_diversity_modes, + .min = 0, + .max = ARRAY_SIZE(phase_diversity_modes) - 1, + }, + + /** + * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in + * diversity mode indicator. Allows user to determine if two + * chips working in diversity mode have established a link + * between each other and if the system as a whole uses + * signals from both antennas to receive FM radio. + */ + [SI476X_IDX_INTERCHIP_LINK] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_INTERCHIP_LINK, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, + .name = "Inter-Chip Link", + .min = 0, + .max = 1, + .step = 1, + }, +}; + +struct si476x_radio; + +/** + * struct si476x_radio_ops - vtable of tuner functions + * + * This table holds pointers to functions implementing particular + * operations depending on the mode in which the tuner chip was + * configured to start in. If the function is not supported + * corresponding element is set to #NULL. + * + * @tune_freq: Tune chip to a specific frequency + * @seek_start: Star station seeking + * @rsq_status: Get Recieved Signal Quality(RSQ) status + * @rds_blckcnt: Get recived RDS blocks count + * @phase_diversity: Change phase diversity mode of the tuner + * @phase_div_status: Get phase diversity mode status + * @acf_status: Get the status of Automatically Controlled + * Features(ACF) + * @agc_status: Get Automatic Gain Control(AGC) status + */ +struct si476x_radio_ops { + int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *); + int (*seek_start)(struct si476x_core *, bool, bool); + int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); + int (*rds_blckcnt)(struct si476x_core *, bool, + struct si476x_rds_blockcount_report *); + + int (*phase_diversity)(struct si476x_core *, + enum si476x_phase_diversity_mode); + int (*phase_div_status)(struct si476x_core *); + int (*acf_status)(struct si476x_core *, + struct si476x_acf_status_report *); + int (*agc_status)(struct si476x_core *, + struct si476x_agc_status_report *); +}; + +/** + * struct si476x_radio - radio device + * + * @core: Pointer to underlying core device + * @videodev: Pointer to video device created by V4L2 subsystem + * @ops: Vtable of functions. See struct si476x_radio_ops for details + * @kref: Reference counter + * @core_lock: An r/w semaphore to brebvent the deletion of underlying + * core structure is the radio device is being used + */ +struct si476x_radio { + struct v4l2_device v4l2dev; + struct video_device videodev; + struct v4l2_ctrl_handler ctrl_handler; + + struct si476x_core *core; + /* This field should not be accesses unless core lock is held */ + const struct si476x_radio_ops *ops; + + struct dentry *debugfs; + u32 audmode; +}; + +static inline struct si476x_radio * +v4l2_dev_to_radio(struct v4l2_device *d) +{ + return container_of(d, struct si476x_radio, v4l2dev); +} + +static inline struct si476x_radio * +v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) +{ + return container_of(d, struct si476x_radio, ctrl_handler); +} + +/* + * si476x_vidioc_querycap - query device capabilities + */ +static int si476x_radio_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + struct si476x_radio *radio = video_drvdata(file); + + strlcpy(capability->driver, radio->v4l2dev.name, + sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + snprintf(capability->bus_info, sizeof(capability->bus_info), + "platform:%s", radio->v4l2dev.name); + + capability->device_caps = V4L2_CAP_TUNER + | V4L2_CAP_RADIO + | V4L2_CAP_HW_FREQ_SEEK; + + si476x_core_lock(radio->core); + if (!si476x_core_is_a_secondary_tuner(radio->core)) + capability->device_caps |= V4L2_CAP_RDS_CAPTURE + | V4L2_CAP_READWRITE; + si476x_core_unlock(radio->core); + + capability->capabilities = capability->device_caps + | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int si476x_radio_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (band->tuner != 0) + return -EINVAL; + + switch (radio->core->chip_id) { + /* AM/FM tuners -- all bands are supported */ + case SI476X_CHIP_SI4761: + case SI476X_CHIP_SI4764: + if (band->index < ARRAY_SIZE(si476x_bands)) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + /* FM companion tuner chips -- only FM bands are + * supported */ + case SI476X_CHIP_SI4768: + if (band->index == SI476X_BAND_FM) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + default: + err = -EINVAL; + } + + return err; +} + +static int si476x_radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + int err; + struct si476x_rsq_status_report report; + struct si476x_radio *radio = video_drvdata(file); + + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + if (tuner->index != 0) + return -EINVAL; + + tuner->type = V4L2_TUNER_RADIO; + tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies + * in multiples of + * 62.5 Hz */ + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_HWSEEK_BOUNDED + | V4L2_TUNER_CAP_HWSEEK_WRAP + | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; + + si476x_core_lock(radio->core); + + if (si476x_core_is_a_secondary_tuner(radio->core)) { + strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); + tuner->rxsubchans = 0; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } else if (si476x_core_has_am(radio->core)) { + if (si476x_core_is_a_primary_tuner(radio->core)) + strlcpy(tuner->name, "AM/FM (primary)", + sizeof(tuner->name)); + else + strlcpy(tuner->name, "AM/FM", sizeof(tuner->name)); + + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO + | V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + + tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; + } else { + strlcpy(tuner->name, "FM", sizeof(tuner->name)); + tuner->rxsubchans = V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } + + tuner->audmode = radio->audmode; + + tuner->afc = 1; + tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; + + err = radio->ops->rsq_status(radio->core, + &args, &report); + if (err < 0) { + tuner->signal = 0; + } else { + /* + * tuner->signal value range: 0x0000 .. 0xFFFF, + * report.rssi: -128 .. 127 + */ + tuner->signal = (report.rssi + 128) * 257; + } + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *tuner) +{ + struct si476x_radio *radio = video_drvdata(file); + + if (tuner->index != 0) + return -EINVAL; + + if (tuner->audmode == V4L2_TUNER_MODE_MONO || + tuner->audmode == V4L2_TUNER_MODE_STEREO) + radio->audmode = tuner->audmode; + else + radio->audmode = V4L2_TUNER_MODE_STEREO; + + return 0; +} + +static int si476x_radio_init_vtable(struct si476x_radio *radio, + enum si476x_func func) +{ + static const struct si476x_radio_ops fm_ops = { + .tune_freq = si476x_core_cmd_fm_tune_freq, + .seek_start = si476x_core_cmd_fm_seek_start, + .rsq_status = si476x_core_cmd_fm_rsq_status, + .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, + .phase_diversity = si476x_core_cmd_fm_phase_diversity, + .phase_div_status = si476x_core_cmd_fm_phase_div_status, + .acf_status = si476x_core_cmd_fm_acf_status, + .agc_status = si476x_core_cmd_agc_status, + }; + + static const struct si476x_radio_ops am_ops = { + .tune_freq = si476x_core_cmd_am_tune_freq, + .seek_start = si476x_core_cmd_am_seek_start, + .rsq_status = si476x_core_cmd_am_rsq_status, + .rds_blckcnt = NULL, + .phase_diversity = NULL, + .phase_div_status = NULL, + .acf_status = si476x_core_cmd_am_acf_status, + .agc_status = NULL, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + radio->ops = &fm_ops; + return 0; + + case SI476X_FUNC_AM_RECEIVER: + radio->ops = &am_ops; + return 0; + default: + WARN(1, "Unexpected tuner function value\n"); + return -EINVAL; + } +} + +static int si476x_radio_pretune(struct si476x_radio *radio, + enum si476x_func func) +{ + int retval; + + struct si476x_tune_freq_args args = { + .zifsr = false, + .hd = false, + .injside = SI476X_INJSIDE_AUTO, + .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, + .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, + .antcap = 0, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 92 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + case SI476X_FUNC_AM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 0.6 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + default: + WARN(1, "Unexpected tuner function value\n"); + retval = -EINVAL; + } + + return retval; +} +static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + + /* regcache_mark_dirty(radio->core->regmap); */ + 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; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + SI476X_PROP_AUDIO_PWR_LINE_FILTER); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_INT_CTL_ENABLE, + SI476X_PROP_INT_CTL_ENABLE); + if (err < 0) + return err; + + /* + * Is there any point in restoring SNR and the like + * when switching between AM/FM? + */ + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + SI476X_PROP_VALID_MAX_TUNE_ERROR); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + SI476X_PROP_VALID_RSSI_THRESHOLD); + if (err < 0) + return err; + + if (func == SI476X_FUNC_FM_RECEIVER) { + if (si476x_core_has_diversity(radio->core)) { + err = si476x_core_cmd_fm_phase_diversity(radio->core, + radio->core->diversity_mode); + if (err < 0) + return err; + } + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_PROP_FM_RDS_CONFIG); + if (err < 0) + return err; + } + + return si476x_radio_init_vtable(radio, func); + +} + +static int si476x_radio_change_func(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + bool soft; + /* + * Since power/up down is a very time consuming operation, + * try to avoid doing it if the requested mode matches the one + * the tuner is in + */ + if (func == radio->core->power_up_parameters.func) + return 0; + + soft = true; + err = si476x_core_stop(radio->core, soft); + if (err < 0) { + /* + * OK, if the chip does not want to play nice let's + * try to reset it in more brutal way + */ + soft = false; + err = si476x_core_stop(radio->core, soft); + if (err < 0) + return err; + } + /* + Set the desired radio tuner function + */ + radio->core->power_up_parameters.func = func; + + err = si476x_core_start(radio->core, soft); + if (err < 0) + return err; + + /* + * No need to do the rest of manipulations for the bootlader + * mode + */ + if (func != SI476X_FUNC_FM_RECEIVER && + func != SI476X_FUNC_AM_RECEIVER) + return err; + + return si476x_radio_do_post_powerup_init(radio, func); +} + +static int si476x_radio_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (radio->ops->rsq_status) { + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = true, + .cancel = false, + .stcack = false, + }; + + err = radio->ops->rsq_status(radio->core, &args, &report); + if (!err) + f->frequency = si476x_to_v4l2(radio->core, + report.readfreq); + } else { + err = -EINVAL; + } + + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_frequency(struct file *file, void *priv, + const struct v4l2_frequency *f) +{ + int err; + u32 freq = f->frequency; + struct si476x_tune_freq_args args; + struct si476x_radio *radio = video_drvdata(file); + + const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + + si476x_bands[SI476X_BAND_FM].rangelow) / 2; + const int band = (freq > midrange) ? + SI476X_BAND_FM : SI476X_BAND_AM; + const enum si476x_func func = (band == SI476X_BAND_AM) ? + SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + freq = clamp(freq, + si476x_bands[band].rangelow, + si476x_bands[band].rangehigh); + + if (si476x_radio_freq_is_inside_of_the_band(freq, + SI476X_BAND_AM) && + (!si476x_core_has_am(radio->core) || + si476x_core_is_a_secondary_tuner(radio->core))) { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + args.zifsr = false; + args.hd = false; + args.injside = SI476X_INJSIDE_AUTO; + args.freq = v4l2_to_si476x(radio->core, freq); + args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; + args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; + args.antcap = 0; + + err = radio->ops->tune_freq(radio->core, &args); + +unlock: + si476x_core_unlock(radio->core); + return err; +} + +static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, + const struct v4l2_hw_freq_seek *seek) +{ + int err; + enum si476x_func func; + u32 rangelow, rangehigh; + struct si476x_radio *radio = video_drvdata(file); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (seek->tuner != 0 || + seek->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (!seek->rangelow) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + &rangelow); + if (!err) + rangelow = si476x_to_v4l2(radio->core, rangelow); + else + goto unlock; + } + if (!seek->rangehigh) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + &rangehigh); + if (!err) + rangehigh = si476x_to_v4l2(radio->core, rangehigh); + else + goto unlock; + } + + if (rangelow > rangehigh) { + err = -EINVAL; + goto unlock; + } + + if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_FM)) { + func = SI476X_FUNC_FM_RECEIVER; + + } else if (si476x_core_has_am(radio->core) && + si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_AM)) { + func = SI476X_FUNC_AM_RECEIVER; + } else { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + if (seek->rangehigh) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + v4l2_to_si476x(radio->core, + seek->rangehigh)); + if (err) + goto unlock; + } + if (seek->rangelow) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + v4l2_to_si476x(radio->core, + seek->rangelow)); + if (err) + goto unlock; + } + if (seek->spacing) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_FREQUENCY_SPACING, + v4l2_to_si476x(radio->core, + seek->spacing)); + if (err) + goto unlock; + } + + err = radio->ops->seek_start(radio->core, + seek->seek_upward, + seek->wrap_around); +unlock: + si476x_core_unlock(radio->core); + + + + return err; +} + +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_INTERCHIP_LINK: + if (si476x_core_has_diversity(radio->core)) { + if (radio->ops->phase_diversity) { + retval = radio->ops->phase_div_status(radio->core); + if (retval < 0) + break; + + ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); + retval = 0; + break; + } else { + retval = -ENOTTY; + break; + } + } + retval = -EINVAL; + break; + default: + retval = -EINVAL; + break; + } + si476x_core_unlock(radio->core); + return retval; + +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + enum si476x_phase_diversity_mode mode; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_HARMONICS_COUNT: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_HARMONICS_MASK, + ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (ctrl->val) { + case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_ENABLE_MASK, + 0); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_50HZ); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_60HZ); + break; + default: + retval = -EINVAL; + break; + } + break; + case V4L2_CID_SI476X_RSSI_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_RSSI_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_SNR_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_MAX_TUNE_ERROR: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + ctrl->val); + break; + case V4L2_CID_RDS_RECEPTION: + /* + * It looks like RDS related properties are + * inaccesable when tuner is in AM mode, so cache the + * changes + */ + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, true); + + if (ctrl->val) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, + radio->core->rds_fifo_depth); + if (retval < 0) + break; + + if (radio->core->client->irq) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_RDSRECV); + if (retval < 0) + break; + } + + /* Drain RDS FIFO before enabling RDS processing */ + retval = si476x_core_cmd_fm_rds_status(radio->core, + false, + true, + true, + NULL); + if (retval < 0) + break; + + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + SI476X_PROP_RDSEN); + } else { + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + !SI476X_PROP_RDSEN); + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, false); + break; + case V4L2_CID_TUNE_DEEMPHASIS: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + ctrl->val); + break; + + case V4L2_CID_SI476X_DIVERSITY_MODE: + mode = si476x_phase_diversity_idx_to_mode(ctrl->val); + + if (mode == radio->core->diversity_mode) { + retval = 0; + break; + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) { + /* + * Diversity cannot be configured while tuner + * is in AM mode so save the changes and carry on. + */ + radio->core->diversity_mode = mode; + retval = 0; + } else { + retval = radio->ops->phase_diversity(radio->core, mode); + if (!retval) + radio->core->diversity_mode = mode; + } + break; + + default: + retval = -EINVAL; + break; + } + + si476x_core_unlock(radio->core); + + return retval; +} + +static int si476x_radio_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + if (chip->match.type == V4L2_CHIP_MATCH_HOST && + v4l2_chip_match_host(&chip->match)) + return 0; + return -EINVAL; +} + + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int si476x_radio_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + int err; + unsigned int value; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + reg->size = 2; + err = regmap_read(radio->core->regmap, + (unsigned int)reg->reg, &value); + reg->val = value; + si476x_core_unlock(radio->core); + + return err; +} +static int si476x_radio_s_register(struct file *file, void *fh, + const struct v4l2_dbg_register *reg) +{ + + int err; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + err = regmap_write(radio->core->regmap, + (unsigned int)reg->reg, + (unsigned int)reg->val); + si476x_core_unlock(radio->core); + + return err; +} +#endif + +static int si476x_radio_fops_open(struct file *file) +{ + struct si476x_radio *radio = video_drvdata(file); + int err; + + err = v4l2_fh_open(file); + if (err) + return err; + + if (v4l2_fh_is_singular_file(file)) { + si476x_core_lock(radio->core); + err = si476x_core_set_power_state(radio->core, + SI476X_POWER_UP_FULL); + if (err < 0) + goto done; + + err = si476x_radio_do_post_powerup_init(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + err = si476x_radio_pretune(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + si476x_core_unlock(radio->core); + /*Must be done after si476x_core_unlock to prevent a deadlock*/ + v4l2_ctrl_handler_setup(&radio->ctrl_handler); + } + + return err; + +power_down: + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); +done: + si476x_core_unlock(radio->core); + v4l2_fh_release(file); + + return err; +} + +static int si476x_radio_fops_release(struct file *file) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (v4l2_fh_is_singular_file(file) && + atomic_read(&radio->core->is_alive)) + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); + + err = v4l2_fh_release(file); + + return err; +} + +static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t rval; + size_t fifo_len; + unsigned int copied; + + struct si476x_radio *radio = video_drvdata(file); + + /* block if no new data available */ + if (kfifo_is_empty(&radio->core->rds_fifo)) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + rval = wait_event_interruptible(radio->core->rds_read_queue, + (!kfifo_is_empty(&radio->core->rds_fifo) || + !atomic_read(&radio->core->is_alive))); + if (rval < 0) + return -EINTR; + + if (!atomic_read(&radio->core->is_alive)) + return -ENODEV; + } + + fifo_len = kfifo_len(&radio->core->rds_fifo); + + if (kfifo_to_user(&radio->core->rds_fifo, buf, + min(fifo_len, count), + &copied) != 0) { + dev_warn(&radio->videodev.dev, + "Error during FIFO to userspace copy\n"); + rval = -EIO; + } else { + rval = (ssize_t)copied; + } + + return rval; +} + +static unsigned int si476x_radio_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si476x_radio *radio = video_drvdata(file); + unsigned long req_events = poll_requested_events(pts); + unsigned int err = v4l2_ctrl_poll(file, pts); + + if (req_events & (POLLIN | POLLRDNORM)) { + if (atomic_read(&radio->core->is_alive)) + poll_wait(file, &radio->core->rds_read_queue, pts); + + if (!atomic_read(&radio->core->is_alive)) + err = POLLHUP; + + if (!kfifo_is_empty(&radio->core->rds_fifo)) + err = POLLIN | POLLRDNORM; + } + + return err; +} + +static const struct v4l2_file_operations si476x_fops = { + .owner = THIS_MODULE, + .read = si476x_radio_fops_read, + .poll = si476x_radio_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = si476x_radio_fops_open, + .release = si476x_radio_fops_release, +}; + + +static const struct v4l2_ioctl_ops si4761_ioctl_ops = { + .vidioc_querycap = si476x_radio_querycap, + .vidioc_g_tuner = si476x_radio_g_tuner, + .vidioc_s_tuner = si476x_radio_s_tuner, + + .vidioc_g_frequency = si476x_radio_g_frequency, + .vidioc_s_frequency = si476x_radio_s_frequency, + .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, + .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_g_chip_ident = si476x_radio_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = si476x_radio_g_register, + .vidioc_s_register = si476x_radio_s_register, +#endif +}; + + +static const struct video_device si476x_viddev_template = { + .fops = &si476x_fops, + .name = DRIVER_NAME, + .release = video_device_release_empty, +}; + + + +static ssize_t si476x_radio_read_acf_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_acf_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->acf_status) + err = radio->ops->acf_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_acf_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_acf_blob, +}; + +static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rds_blockcount_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rds_blckcnt(radio->core, true, + &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rds_blckcnt_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rds_blckcnt_blob, +}; + +static ssize_t si476x_radio_read_agc_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_agc_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->agc_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_agc_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_agc_blob, +}; + +static ssize_t si476x_radio_read_rsq_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_blob, +}; + +static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = true, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_primary_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_primary_blob, +}; + + +static int si476x_radio_init_debugfs(struct si476x_radio *radio) +{ + struct dentry *dentry; + int ret; + + dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto exit; + } + radio->debugfs = dentry; + + dentry = debugfs_create_file("acf", S_IRUGO, + radio->debugfs, radio, &radio_acf_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rds_blckcnt", S_IRUGO, + radio->debugfs, radio, + &radio_rds_blckcnt_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("agc", S_IRUGO, + radio->debugfs, radio, &radio_agc_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq", S_IRUGO, + radio->debugfs, radio, &radio_rsq_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq_primary", S_IRUGO, + radio->debugfs, radio, + &radio_rsq_primary_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + return 0; +cleanup: + debugfs_remove_recursive(radio->debugfs); +exit: + return ret; +} + + +static int si476x_radio_add_new_custom(struct si476x_radio *radio, + enum si476x_ctrl_idx idx) +{ + int rval; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, + &si476x_ctrls[idx], + NULL); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) + dev_err(radio->v4l2dev.dev, + "Could not initialize '%s' control %d\n", + si476x_ctrls[idx].name, rval); + + return rval; +} + +static int si476x_radio_probe(struct platform_device *pdev) +{ + int rval; + struct si476x_radio *radio; + struct v4l2_ctrl *ctrl; + + static atomic_t instance = ATOMIC_INIT(0); + + radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); + if (!radio) + return -ENOMEM; + + radio->core = i2c_mfd_cell_to_core(&pdev->dev); + + v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); + + rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); + if (rval) { + dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); + return rval; + } + + memcpy(&radio->videodev, &si476x_viddev_template, + sizeof(struct video_device)); + + radio->videodev.v4l2_dev = &radio->v4l2dev; + radio->videodev.ioctl_ops = &si4761_ioctl_ops; + + video_set_drvdata(&radio->videodev, radio); + platform_set_drvdata(pdev, radio); + + set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); + + radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; + v4l2_ctrl_handler_init(&radio->ctrl_handler, + 1 + ARRAY_SIZE(si476x_ctrls)); + + if (si476x_core_has_am(radio->core)) { + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", + rval); + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, + SI476X_IDX_HARMONICS_COUNT); + if (rval < 0) + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); + if (rval < 0) + goto exit; + + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_TUNE_DEEMPHASIS, + V4L2_DEEMPHASIS_75_uS, 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", + rval); + goto exit; + } + + ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, + V4L2_CID_RDS_RECEPTION, + 0, 1, 1, 1); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", + rval); + goto exit; + } + + if (si476x_core_has_diversity(radio->core)) { + si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = + si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); + si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); + if (rval < 0) + goto exit; + + si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); + if (rval < 0) + goto exit; + } + + /* register video device */ + rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); + if (rval < 0) { + dev_err(&pdev->dev, "Could not register video device\n"); + goto exit; + } + + rval = si476x_radio_init_debugfs(radio); + if (rval < 0) { + dev_err(&pdev->dev, "Could not creat debugfs interface\n"); + goto exit; + } + + return 0; +exit: + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + return rval; +} + +static int si476x_radio_remove(struct platform_device *pdev) +{ + struct si476x_radio *radio = platform_get_drvdata(pdev); + + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + video_unregister_device(&radio->videodev); + v4l2_device_unregister(&radio->v4l2dev); + debugfs_remove_recursive(radio->debugfs); + + return 0; +} + +MODULE_ALIAS("platform:si476x-radio"); + +static struct platform_driver si476x_radio_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = si476x_radio_probe, + .remove = si476x_radio_remove, +}; +module_platform_driver(si476x_radio_driver); + +MODULE_AUTHOR("Andrey Smirnov "); +MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); +MODULE_LICENSE("GPL"); diff --git a/include/media/si476x.h b/include/media/si476x.h new file mode 100644 index 000000000000..e02e241e2d22 --- /dev/null +++ b/include/media/si476x.h @@ -0,0 +1,37 @@ +/* + * include/media/si476x.h -- Common definitions for si476x driver + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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 SI476X_H +#define SI476X_H + +#include +#include + +#include + +enum si476x_ctrl_id { + V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1), + V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2), + V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3), + V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4), + V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5), + V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6), +}; + +#endif /* SI476X_H*/ -- cgit v1.2.3 From cb132cd5d75f6cd3295c2c041177eeb89f778db8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 17 Apr 2013 08:22:15 -0300 Subject: [media] videobuf-dma-contig: remove support for cached mem videobuf_queue_dma_contig_init_cached() is not used anywhere. Drop support for it, cleaning up the code a little bit. Signed-off-by: Mauro Carvalho Chehab Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf-dma-contig.c | 130 +++----------------------- include/media/videobuf-dma-contig.h | 10 -- 2 files changed, 14 insertions(+), 126 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index 3a43ba0959bf..67f572c3fba2 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -27,7 +27,6 @@ struct videobuf_dma_contig_memory { u32 magic; void *vaddr; dma_addr_t dma_handle; - bool cached; unsigned long size; }; @@ -43,26 +42,8 @@ static int __videobuf_dc_alloc(struct device *dev, unsigned long size, gfp_t flags) { mem->size = size; - if (mem->cached) { - mem->vaddr = alloc_pages_exact(mem->size, flags | GFP_DMA); - if (mem->vaddr) { - int err; - - mem->dma_handle = dma_map_single(dev, mem->vaddr, - mem->size, - DMA_FROM_DEVICE); - err = dma_mapping_error(dev, mem->dma_handle); - if (err) { - dev_err(dev, "dma_map_single failed\n"); - - free_pages_exact(mem->vaddr, mem->size); - mem->vaddr = NULL; - return err; - } - } - } else - mem->vaddr = dma_alloc_coherent(dev, mem->size, - &mem->dma_handle, flags); + mem->vaddr = dma_alloc_coherent(dev, mem->size, + &mem->dma_handle, flags); if (!mem->vaddr) { dev_err(dev, "memory alloc size %ld failed\n", mem->size); @@ -77,14 +58,7 @@ static int __videobuf_dc_alloc(struct device *dev, static void __videobuf_dc_free(struct device *dev, struct videobuf_dma_contig_memory *mem) { - if (mem->cached) { - if (!mem->vaddr) - return; - dma_unmap_single(dev, mem->dma_handle, mem->size, - DMA_FROM_DEVICE); - free_pages_exact(mem->vaddr, mem->size); - } else - dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle); + dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle); mem->vaddr = NULL; } @@ -234,7 +208,7 @@ out_up: return ret; } -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached) +static struct videobuf_buffer *__videobuf_alloc(size_t size) { struct videobuf_dma_contig_memory *mem; struct videobuf_buffer *vb; @@ -244,22 +218,11 @@ static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached) vb->priv = ((char *)vb) + size; mem = vb->priv; mem->magic = MAGIC_DC_MEM; - mem->cached = cached; } return vb; } -static struct videobuf_buffer *__videobuf_alloc_uncached(size_t size) -{ - return __videobuf_alloc_vb(size, false); -} - -static struct videobuf_buffer *__videobuf_alloc_cached(size_t size) -{ - return __videobuf_alloc_vb(size, true); -} - static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) { struct videobuf_dma_contig_memory *mem = buf->priv; @@ -310,19 +273,6 @@ static int __videobuf_iolock(struct videobuf_queue *q, return 0; } -static int __videobuf_sync(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size, - DMA_FROM_DEVICE); - - return 0; -} - static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct videobuf_buffer *buf, struct vm_area_struct *vma) @@ -331,8 +281,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct videobuf_mapping *map; int retval; unsigned long size; - unsigned long pos, start = vma->vm_start; - struct page *page; dev_dbg(q->dev, "%s\n", __func__); @@ -359,43 +307,16 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, size = vma->vm_end - vma->vm_start; size = (size < mem->size) ? size : mem->size; - if (!mem->cached) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - retval = remap_pfn_range(vma, vma->vm_start, - mem->dma_handle >> PAGE_SHIFT, + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + retval = remap_pfn_range(vma, vma->vm_start, + mem->dma_handle >> PAGE_SHIFT, size, vma->vm_page_prot); - if (retval) { - dev_err(q->dev, "mmap: remap failed with error %d. ", - retval); - dma_free_coherent(q->dev, mem->size, - mem->vaddr, mem->dma_handle); - goto error; - } - } else { - pos = (unsigned long)mem->vaddr; - - while (size > 0) { - page = virt_to_page((void *)pos); - if (NULL == page) { - dev_err(q->dev, "mmap: virt_to_page failed\n"); - __videobuf_dc_free(q->dev, mem); - goto error; - } - retval = vm_insert_page(vma, start, page); - if (retval) { - dev_err(q->dev, "mmap: insert failed with error %d\n", - retval); - __videobuf_dc_free(q->dev, mem); - goto error; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } + if (retval) { + dev_err(q->dev, "mmap: remap failed with error %d. ", + retval); + dma_free_coherent(q->dev, mem->size, + mem->vaddr, mem->dma_handle); + goto error; } vma->vm_ops = &videobuf_vm_ops; @@ -417,17 +338,8 @@ error: static struct videobuf_qtype_ops qops = { .magic = MAGIC_QTYPE_OPS, - .alloc_vb = __videobuf_alloc_uncached, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -static struct videobuf_qtype_ops qops_cached = { - .magic = MAGIC_QTYPE_OPS, - .alloc_vb = __videobuf_alloc_cached, + .alloc_vb = __videobuf_alloc, .iolock = __videobuf_iolock, - .sync = __videobuf_sync, .mmap_mapper = __videobuf_mmap_mapper, .vaddr = __videobuf_to_vaddr, }; @@ -447,20 +359,6 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q, } EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init); -void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops_cached, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init_cached); - dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf) { struct videobuf_dma_contig_memory *mem = buf->priv; diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h index f473aeb86d3f..f0ed82543d9f 100644 --- a/include/media/videobuf-dma-contig.h +++ b/include/media/videobuf-dma-contig.h @@ -26,16 +26,6 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q, void *priv, struct mutex *ext_lock); -void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf); -- cgit v1.2.3 From 4ed7e7bae6a4edc90bfa82b55716e4000b584436 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 20 Apr 2013 12:07:16 -0300 Subject: [media] videodev2.h: Remove the unused old V4L1 buffer types Those aren't used anywhere for a long time. Drop it. Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 97fb392bb2d9..f40b41c7e108 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -72,27 +72,6 @@ #define VIDEO_MAX_FRAME 32 #define VIDEO_MAX_PLANES 8 -#ifndef __KERNEL__ - -/* These defines are V4L1 specific and should not be used with the V4L2 API! - They will be removed from this header in the future. */ - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ -#endif - /* * M I S C E L L A N E O U S */ -- cgit v1.2.3