From 0d71a5b1e67685e20608b2b2c1cab61039ee2168 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Feb 2009 09:06:13 -0300 Subject: em28xx: VideoMate For You USB TV box requires tvaudio From: Mauro Carvalho Chehab As reported by Vitaly Wool : > about half a year ago I posted the patch that basically enabled Compro > VideoMate For You USB TV box support. > The main problem is I couldn't get the sound working. > So I kind of decomposed the box and found out the audio decoder chip > used there was Philips TDA9874A. As far as I can see, it's not supported > within the em28xx suite although it is for other TV tuner drivers. A tvaudio modprobing confirms that tda9874a chip is accessible via i2c: tvaudio: TV audio decoder + audio/video mux driver tvaudio: known chips: tda9840, tda9873h, tda9874h/a, tda9850, tda9855, tea6300, tea6320, tea6420, tda8425, pic16c54 (PV951), ta8874z tvaudio' 1-0058: chip found @ 0xb0 tvaudio' 1-0058: tvaudio': chip_read2: reg254=0x11 tvaudio' 1-0058: tvaudio': chip_read2: reg255=0x2 tvaudio' 1-0058: tda9874a_checkit(): DIC=0x11, SIC=0x2. tvaudio' 1-0058: found tda9874a. tvaudio' 1-0058: tda9874h/a found @ 0xb0 (em28xx #0) tvaudio' 1-0058: tda9874h/a: chip_write: reg0=0x0 tvaudio' 1-0058: tda9874h/a: chip_write: reg1=0xc0 tvaudio' 1-0058: tda9874h/a: chip_write: reg2=0x2 tvaudio' 1-0058: tda9874h/a: chip_write: reg11=0x80 tvaudio' 1-0058: tda9874h/a: chip_write: reg12=0x0 tvaudio' 1-0058: tda9874h/a: chip_write: reg13=0x0 tvaudio' 1-0058: tda9874h/a: chip_write: reg14=0x1 tvaudio' 1-0058: tda9874h/a: chip_write: reg15=0x0 tvaudio' 1-0058: tda9874h/a: chip_write: reg16=0x14 tvaudio' 1-0058: tda9874h/a: chip_write: reg17=0x50 tvaudio' 1-0058: tda9874h/a: chip_write: reg18=0xf9 tvaudio' 1-0058: tda9874h/a: chip_write: reg19=0x80 tvaudio' 1-0058: tda9874h/a: chip_write: reg20=0x80 tvaudio' 1-0058: tda9874h/a: chip_write: reg24=0x80 tvaudio' 1-0058: tda9874h/a: chip_write: reg255=0x0 tvaudio' 1-0058: tda9874a_setup(): A2, B/G [0x00]. tvaudio' 1-0058: tda9874h/a: thread started] This patch automatically loads tvaudio when needed (currently, only with this board). Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 3 +++ linux/drivers/media/video/em28xx/em28xx.h | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 5af4c417a..bab6340da 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -1309,6 +1309,7 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_TVP5150, + .adecoder = EM28XX_TVAUDIO, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -1986,6 +1987,8 @@ void em28xx_card_setup(struct em28xx *dev) request_module("tvp5150"); if (dev->board.tuner_type != TUNER_ABSENT) request_module("tuner"); + if (dev->board.adecoder == EM28XX_TVAUDIO) + request_module("tvaudio"); #endif em28xx_config_tuner(dev); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 4aebda6c7..e21f29b99 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -358,6 +358,11 @@ enum em28xx_decoder { EM28XX_SAA711X, }; +enum em28xx_adecoder { + EM28XX_NOADECODER = 0, + EM28XX_TVAUDIO, +}; + struct em28xx_board { char *name; int vchannels; @@ -383,6 +388,7 @@ struct em28xx_board { unsigned char xclk, i2c_speed; enum em28xx_decoder decoder; + enum em28xx_adecoder adecoder; struct em28xx_input input[MAX_EM28XX_INPUT]; struct em28xx_input radio; -- cgit v1.2.3 From 5c190e9dc01651545a2cb6e709953984ebae4be2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 12 Jan 2009 10:17:43 +0100 Subject: tvp514x: make the module aware of rich people From: Sebastian Andrzej Siewior because they might design two of those chips on a single board. You never know. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/tvp514x.c | 106 ++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 46 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/tvp514x.c b/linux/drivers/media/video/tvp514x.c index 5f4cbc2b2..f0b2b8ed2 100644 --- a/linux/drivers/media/video/tvp514x.c +++ b/linux/drivers/media/video/tvp514x.c @@ -86,9 +86,12 @@ struct tvp514x_std_info { struct v4l2_standard standard; }; +static struct tvp514x_reg tvp514x_reg_list_default[0x40]; /** - * struct tvp514x_decoded - TVP5146/47 decoder object + * struct tvp514x_decoder - TVP5146/47 decoder object * @v4l2_int_device: Slave handle + * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device + * @tvp514x_regs: copy of hw's regs with preset values. * @pdata: Board specific * @client: I2C client data * @id: Entry from I2C table @@ -103,7 +106,9 @@ struct tvp514x_std_info { * @route: input and output routing at chip level */ struct tvp514x_decoder { - struct v4l2_int_device *v4l2_int_device; + struct v4l2_int_device v4l2_int_device; + struct v4l2_int_slave tvp514x_slave; + struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)]; const struct tvp514x_platform_data *pdata; struct i2c_client *client; @@ -124,7 +129,7 @@ struct tvp514x_decoder { }; /* TVP514x default register values */ -static struct tvp514x_reg tvp514x_reg_list[] = { +static struct tvp514x_reg tvp514x_reg_list_default[] = { {TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */ {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F}, {TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */ @@ -422,7 +427,7 @@ static int tvp514x_configure(struct tvp514x_decoder *decoder) /* common register initialization */ err = - tvp514x_write_regs(decoder->client, tvp514x_reg_list); + tvp514x_write_regs(decoder->client, decoder->tvp514x_regs); if (err) return err; @@ -580,7 +585,8 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id) return err; decoder->current_std = i; - tvp514x_reg_list[REG_VIDEO_STD].val = decoder->std_list[i].video_std; + decoder->tvp514x_regs[REG_VIDEO_STD].val = + decoder->std_list[i].video_std; v4l_dbg(1, debug, decoder->client, "Standard set to: %s", decoder->std_list[i].standard.name); @@ -625,8 +631,8 @@ static int ioctl_s_routing(struct v4l2_int_device *s, if (err) return err; - tvp514x_reg_list[REG_INPUT_SEL].val = input_sel; - tvp514x_reg_list[REG_OUTPUT_FORMATTER1].val = output_sel; + decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel; + decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel; /* Clear status */ msleep(LOCK_RETRY_DELAY); @@ -779,16 +785,16 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - ctrl->value = tvp514x_reg_list[REG_BRIGHTNESS].val; + ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val; break; case V4L2_CID_CONTRAST: - ctrl->value = tvp514x_reg_list[REG_CONTRAST].val; + ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val; break; case V4L2_CID_SATURATION: - ctrl->value = tvp514x_reg_list[REG_SATURATION].val; + ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val; break; case V4L2_CID_HUE: - ctrl->value = tvp514x_reg_list[REG_HUE].val; + ctrl->value = decoder->tvp514x_regs[REG_HUE].val; if (ctrl->value == 0x7F) ctrl->value = 180; else if (ctrl->value == 0x80) @@ -798,7 +804,7 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) break; case V4L2_CID_AUTOGAIN: - ctrl->value = tvp514x_reg_list[REG_AFE_GAIN_CTRL].val; + ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val; if ((ctrl->value & 0x3) == 3) ctrl->value = 1; else @@ -848,7 +854,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) value); if (err) return err; - tvp514x_reg_list[REG_BRIGHTNESS].val = value; + decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; break; case V4L2_CID_CONTRAST: if (ctrl->value < 0 || ctrl->value > 255) { @@ -861,7 +867,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) value); if (err) return err; - tvp514x_reg_list[REG_CONTRAST].val = value; + decoder->tvp514x_regs[REG_CONTRAST].val = value; break; case V4L2_CID_SATURATION: if (ctrl->value < 0 || ctrl->value > 255) { @@ -874,7 +880,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) value); if (err) return err; - tvp514x_reg_list[REG_SATURATION].val = value; + decoder->tvp514x_regs[REG_SATURATION].val = value; break; case V4L2_CID_HUE: if (value == 180) @@ -893,7 +899,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) value); if (err) return err; - tvp514x_reg_list[REG_HUE].val = value; + decoder->tvp514x_regs[REG_HUE].val = value; break; case V4L2_CID_AUTOGAIN: if (value == 1) @@ -910,7 +916,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl) value); if (err) return err; - tvp514x_reg_list[REG_AFE_GAIN_CTRL].val = value; + decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; break; default: v4l_err(decoder->client, @@ -1275,7 +1281,7 @@ static int ioctl_init(struct v4l2_int_device *s) struct tvp514x_decoder *decoder = s->priv; /* Set default standard to auto */ - tvp514x_reg_list[REG_VIDEO_STD].val = + decoder->tvp514x_regs[REG_VIDEO_STD].val = VIDEO_STD_AUTO_SWITCH_BIT; return tvp514x_configure(decoder); @@ -1344,11 +1350,6 @@ static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = { (v4l2_int_ioctl_func *) ioctl_s_routing}, }; -static struct v4l2_int_slave tvp514x_slave = { - .ioctls = tvp514x_ioctl_desc, - .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc), -}; - static struct tvp514x_decoder tvp514x_dev = { .state = STATE_NOT_DETECTED, @@ -1369,17 +1370,15 @@ static struct tvp514x_decoder tvp514x_dev = { .current_std = STD_NTSC_MJ, .std_list = tvp514x_std_list, .num_stds = ARRAY_SIZE(tvp514x_std_list), - -}; - -static struct v4l2_int_device tvp514x_int_device = { - .module = THIS_MODULE, - .name = TVP514X_MODULE_NAME, - .priv = &tvp514x_dev, - .type = v4l2_int_type_slave, - .u = { - .slave = &tvp514x_slave, - }, + .v4l2_int_device = { + .module = THIS_MODULE, + .name = TVP514X_MODULE_NAME, + .type = v4l2_int_type_slave, + }, + .tvp514x_slave = { + .ioctls = tvp514x_ioctl_desc, + .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc), + }, }; /** @@ -1392,26 +1391,37 @@ static struct v4l2_int_device tvp514x_int_device = { static int tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tvp514x_decoder *decoder = &tvp514x_dev; + struct tvp514x_decoder *decoder; int err; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - decoder->pdata = client->dev.platform_data; - if (!decoder->pdata) { + decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); + if (!decoder) + return -ENOMEM; + + if (!client->dev.platform_data) { v4l_err(client, "No platform data!!\n"); - return -ENODEV; + err = -ENODEV; + goto out_free; } + + *decoder = tvp514x_dev; + decoder->v4l2_int_device.priv = decoder; + decoder->pdata = client->dev.platform_data; + decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave; + memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, + sizeof(tvp514x_reg_list_default)); /* * Fetch platform specific data, and configure the * tvp514x_reg_list[] accordingly. Since this is one * time configuration, no need to preserve. */ - tvp514x_reg_list[REG_OUTPUT_FORMATTER2].val |= + decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |= (decoder->pdata->clk_polarity << 1); - tvp514x_reg_list[REG_SYNC_CONTROL].val |= + decoder->tvp514x_regs[REG_SYNC_CONTROL].val |= ((decoder->pdata->hs_polarity << 2) | (decoder->pdata->vs_polarity << 3)); /* @@ -1419,23 +1429,27 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) */ decoder->id = (struct i2c_device_id *)id; /* Attach to Master */ - strcpy(tvp514x_int_device.u.slave->attach_to, decoder->pdata->master); - decoder->v4l2_int_device = &tvp514x_int_device; + strcpy(decoder->v4l2_int_device.u.slave->attach_to, + decoder->pdata->master); decoder->client = client; i2c_set_clientdata(client, decoder); /* Register with V4L2 layer as slave device */ - err = v4l2_int_device_register(decoder->v4l2_int_device); + err = v4l2_int_device_register(&decoder->v4l2_int_device); if (err) { i2c_set_clientdata(client, NULL); v4l_err(client, "Unable to register to v4l2. Err[%d]\n", err); + goto out_free; } else v4l_info(client, "Registered to v4l2 master %s!!\n", decoder->pdata->master); - return 0; + +out_free: + kfree(decoder); + return err; } /** @@ -1452,9 +1466,9 @@ static int __exit tvp514x_remove(struct i2c_client *client) if (!client->adapter) return -ENODEV; /* our client isn't attached */ - v4l2_int_device_unregister(decoder->v4l2_int_device); + v4l2_int_device_unregister(&decoder->v4l2_int_device); i2c_set_clientdata(client, NULL); - + kfree(decoder); return 0; } /* -- cgit v1.2.3 From bdff40c8e0a3b0971c67f28db1b0f9b2fe581313 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 14 Feb 2009 23:26:56 +0100 Subject: uvcvideo: Initialize streaming parameters with the probe control value From: Laurent Pinchart The UVC specification requires SET_CUR requests on the streaming commit control to use values retrieved from a successful GET_CUR request on the probe control. Initialize streaming parameters with the probe control current value to make sure the driver always complies. Priority: normal Signed-off-by: Laurent Pinchart --- linux/drivers/media/video/uvc/uvc_video.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 04c791213..a4034ccb2 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -1030,11 +1030,20 @@ int uvc_video_init(struct uvc_video_device *video) */ usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); - /* Some webcams don't suport GET_DEF requests on the probe control. We - * fall back to GET_CUR if GET_DEF fails. + /* Set the streaming probe control with default streaming parameters + * retrieved from the device. Webcams that don't suport GET_DEF + * requests on the probe control will just keep their current streaming + * parameters. */ - if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 && - (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0) + if (uvc_get_video_ctrl(video, probe, 1, GET_DEF) == 0) + uvc_set_video_ctrl(video, probe, 1); + + /* Initialize the streaming parameters with the probe control current + * value. This makes sure SET_CUR requests on the streaming commit + * control will always use values retrieved from a successful GET_CUR + * request on the probe control, as required by the UVC specification. + */ + if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0) return ret; /* Check if the default format descriptor exists. Use the first -- cgit v1.2.3 From e2a760f26ff7124de2bc6bed4647962dd7078d1b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 14 Feb 2009 23:39:08 +0100 Subject: uvcvideo: Ignore empty bulk URBs From: Laurent Pinchart Devices may send a zero-length packet to signal the end of a bulk payload. If the payload size is a multiple of the URB size the zero-length packet will be received by the URB completion handler. Handle this by ignoring all empty URBs. Priority: normal Signed-off-by: Laurent Pinchart --- linux/drivers/media/video/uvc/uvc_video.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index a4034ccb2..328910855 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -540,6 +540,9 @@ static void uvc_video_decode_bulk(struct urb *urb, u8 *mem; int len, ret; + if (urb->actual_length == 0) + return; + mem = urb->transfer_buffer; len = urb->actual_length; video->bulk.payload_size += len; -- cgit v1.2.3 From b25818a3a4e324f54c59786922c73867af099253 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Feb 2009 21:41:52 +0100 Subject: uvcvideo: Add quirk to override wrong bandwidth value for Vimicro devices From: Laurent Pinchart At least 3 Vimicro cameras (0x332d, 0x3410 and 0x3420) fail to return correct bandwidth information. The first model rounds the value provided by the host to the nearest supported packet size, while the other two always request the maximum bandwidth. Introduce a device quirk to override the value returned by the device with an estimated bandwidth computed by the driver from the frame size and frame rate, and enable it for all Vimicro cameras. Priority: normal Signed-off-by: Laurent Pinchart --- linux/drivers/media/video/uvc/uvc_driver.c | 9 ++++++++ linux/drivers/media/video/uvc/uvc_video.c | 34 ++++++++++++++++++++++++++---- linux/drivers/media/video/uvc/uvcvideo.h | 1 + 3 files changed, 40 insertions(+), 4 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 2a41eb418..0d2d87198 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -1863,6 +1863,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, + /* ViMicro */ + { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0ac8, + .idProduct = 0x0000, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, /* MT6227 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 328910855..82a9999b6 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, return 0; } -static void uvc_fixup_buffer_size(struct uvc_video_device *video, +static void uvc_fixup_video_ctrl(struct uvc_video_device *video, struct uvc_streaming_control *ctrl) { struct uvc_format *format; @@ -84,6 +84,31 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video, video->dev->uvc_version < 0x0110)) ctrl->dwMaxVideoFrameSize = frame->dwMaxVideoFrameBufferSize; + + if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH && + video->streaming->intf->num_altsetting > 1) { + u32 interval; + u32 bandwidth; + + interval = (ctrl->dwFrameInterval > 100000) + ? ctrl->dwFrameInterval + : frame->dwFrameInterval[0]; + + /* Compute a bandwidth estimation by multiplying the frame + * size by the number of video frames per second, divide the + * result by the number of USB frames (or micro-frames for + * high-speed devices) per second and add the UVC header size + * (assumed to be 12 bytes long). + */ + bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp; + bandwidth *= 10000000 / interval + 1; + bandwidth /= 1000; + if (video->dev->udev->speed == USB_SPEED_HIGH) + bandwidth /= 8; + bandwidth += 12; + + ctrl->dwMaxPayloadTransferSize = bandwidth; + } } static int uvc_get_video_ctrl(struct uvc_video_device *video, @@ -158,10 +183,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, ctrl->bMaxVersion = 0; } - /* Some broken devices return a null or wrong dwMaxVideoFrameSize. - * Try to get the value from the format and frame descriptors. + /* Some broken devices return null or wrong dwMaxVideoFrameSize and + * dwMaxPayloadTransferSize fields. Try to get the value from the + * format and frame descriptors. */ - uvc_fixup_buffer_size(video, ctrl); + uvc_fixup_video_ctrl(video, ctrl); ret = 0; out: diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index 408b8b846..53d5c9e0c 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -315,6 +315,7 @@ struct uvc_xu_control { #define UVC_QUIRK_STREAM_NO_FID 0x00000010 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 #define UVC_QUIRK_PRUNE_CONTROLS 0x00000040 +#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 -- cgit v1.2.3 From fbef599baf91dd9e8d3926f440a4087b8eaaaeb1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:11:25 +0100 Subject: soc-camera: fix S_CROP breakage on PXA and SuperH From: Guennadi Liakhovetski Recent format-negotiation patches caused S_CROP breakage in pxa_camera.c and sh_mobile_ceu_camera.c drivers, fix it. Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/pxa_camera.c | 26 +++++++++++++------------- drivers/media/video/sh_mobile_ceu_camera.c | 13 +++++-------- 2 files changed, 18 insertions(+), 21 deletions(-) --- linux/drivers/media/video/pxa_camera.c | 26 ++++++++++++------------ linux/drivers/media/video/sh_mobile_ceu_camera.c | 13 +++++------- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c index 2c283b82a..b6a34ba18 100644 --- a/linux/drivers/media/video/pxa_camera.c +++ b/linux/drivers/media/video/pxa_camera.c @@ -1164,23 +1164,23 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; - const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL; - const struct soc_camera_format_xlate *xlate; + const struct soc_camera_data_format *cam_fmt = NULL; + const struct soc_camera_format_xlate *xlate = NULL; struct soc_camera_sense sense = { .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; - int ret, buswidth; + int ret; - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); - return -EINVAL; - } + if (pixfmt) { + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } - buswidth = xlate->buswidth; - host_fmt = xlate->host_fmt; - cam_fmt = xlate->cam_fmt; + cam_fmt = xlate->cam_fmt; + } /* If PCLK is used to latch data from the sensor, check sense */ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) @@ -1210,8 +1210,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, } if (pixfmt && !ret) { - icd->buswidth = buswidth; - icd->current_fmt = host_fmt; + icd->buswidth = xlate->buswidth; + icd->current_fmt = xlate->host_fmt; } return ret; diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index ae98eaf5f..ee113de47 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -604,21 +604,18 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; int ret; + if (!pixfmt) + return icd->ops->set_fmt(icd, pixfmt, rect); + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { dev_warn(&ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } - switch (pixfmt) { - case 0: /* Only geometry change */ - ret = icd->ops->set_fmt(icd, pixfmt, rect); - break; - default: - ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect); - } + ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect); - if (pixfmt && !ret) { + if (!ret) { icd->buswidth = xlate->buswidth; icd->current_fmt = xlate->host_fmt; pcdev->camera_fmt = xlate->cam_fmt; -- cgit v1.2.3 From 0992bac9732a651a2024c68cdf87bcd54fa1e381 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 19 Feb 2009 16:41:56 +0000 Subject: em28xx: register device to soundcard for sysfs From: Nicola Soranzo As explained in "Writing an ALSA driver" (T. Iwai), audio drivers should set the struct device for the card before registering the card instance. This will add the correct /sys/class/sound/cardN/device symlink, so HAL can see the device and ConsoleKit sets its ACL permissions for the logged-in user. For em28xx audio capture cards found e.g. in Hauppauge WinTV-HVR-900 (R2), this patch fixes errors like: ALSA lib pcm_hw.c:1429:(_snd_pcm_hw_open) Invalid value for card Error opening audio: Permission denied when running mplayer as a normal user. Priority: normal Signed-off-by: Nicola Soranzo Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-audio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index bfa3986f5..eb49a1364 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -560,6 +560,8 @@ static int em28xx_audio_init(struct em28xx *dev) pcm->info_flags = 0; pcm->private_data = dev; strcpy(pcm->name, "Empia 28xx Capture"); + + snd_card_set_dev(card, &dev->udev->dev); strcpy(card->driver, "Empia Em28xx Audio"); strcpy(card->shortname, "Em28xx Audio"); strcpy(card->longname, "Empia Em28xx Audio"); -- cgit v1.2.3 From e9e48721ed72a07c7d841000bfaeda024af28217 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Thu, 19 Feb 2009 19:34:48 +0100 Subject: gspca - sonixj: Handle the webcam 0c45:613c instead of sn9c102. From: Jean-Francois Moine Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/sonixj.c | 2 +- linux/drivers/media/video/sn9c102/sn9c102_devtable.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 5cdb643b8..36d6f50be 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -2199,9 +2199,9 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, +#endif {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, /* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */ -#endif {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, {} }; diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h index 8cb3457e7..41dfb60f4 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -123,7 +123,9 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, #endif { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, { } }; -- cgit v1.2.3 From 36c7a4cef04513ddb801f8b65ce0b8fcc0228d87 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Thu, 19 Feb 2009 19:38:31 +0100 Subject: gspca - zc3xx: Bad probe of the ov7xxx sensors. From: Jean-Francois Moine This patch fixes one bug of the kernel bug report 12737. Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/zc3xx.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index b93573f66..c885146cc 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -7016,7 +7016,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) static int zcxx_probeSensor(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int sensor, sensor2; + int sensor; switch (sd->sensor) { case SENSOR_MC501CB: @@ -7031,16 +7031,9 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) break; } sensor = vga_2wr_probe(gspca_dev); - if (sensor >= 0) { - if (sensor < 0x7600) - return sensor; - /* next probe is needed for OmniVision ? */ - } - sensor2 = vga_3wr_probe(gspca_dev); - if (sensor2 >= 0 - && sensor >= 0) + if (sensor >= 0) return sensor; - return sensor2; + return vga_3wr_probe(gspca_dev); } /* this function is called at probe time */ -- cgit v1.2.3 From 34a37624e9b1eb3c2c938700af69d147ee3e6a7d Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Thu, 19 Feb 2009 19:41:28 +0100 Subject: gspca - zc3xx: Bad probe of the ov7630c sensor. From: Jean-Francois Moine This patch fixes an other bug of the kernel bug report 12737. Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/zc3xx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index c885146cc..ad385b9a0 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -7170,6 +7170,10 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Find Sensor OV7620"); sd->sensor = SENSOR_OV7620; break; + case 0x7631: + PDEBUG(D_PROBE, "Find Sensor OV7630C"); + sd->sensor = SENSOR_OV7630C; + break; case 0x7648: PDEBUG(D_PROBE, "Find Sensor OV7648"); sd->sensor = SENSOR_OV7620; /* same sensor (?) */ -- cgit v1.2.3 From b2e7077468076b3bfb3f6ad572808dab4a8795ae Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Feb 2009 09:50:52 +0100 Subject: v4l2: add colorfx support to v4l2-common.c, and add to 'Changes' in spec. From: Hans Verkuil Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 8ae8dd366..ec81afb19 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -335,6 +335,12 @@ const char **v4l2_ctrl_get_menu(u32 id) "Aperture Priority Mode", NULL }; + static const char *colorfx[] = { + "None", + "Black & White", + "Sepia", + NULL + }; switch (id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: @@ -371,6 +377,8 @@ const char **v4l2_ctrl_get_menu(u32 id) return camera_power_line_frequency; case V4L2_CID_EXPOSURE_AUTO: return camera_exposure_auto; + case V4L2_CID_COLORFX: + return colorfx; default: return NULL; } @@ -413,6 +421,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation"; case V4L2_CID_CHROMA_AGC: return "Chroma AGC"; case V4L2_CID_COLOR_KILLER: return "Color Killer"; + case V4L2_CID_COLORFX: return "Color Effects"; /* MPEG controls */ case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls"; @@ -518,6 +527,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_MPEG_STREAM_TYPE: case V4L2_CID_MPEG_STREAM_VBI_FMT: case V4L2_CID_EXPOSURE_AUTO: + case V4L2_CID_COLORFX: qctrl->type = V4L2_CTRL_TYPE_MENU; step = 1; break; @@ -586,6 +596,8 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64); case V4L2_CID_HUE: return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0); + case V4L2_CID_COLORFX: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); /* MPEG controls */ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: -- cgit v1.2.3 From 28258187ce09827121e04b2de19e454032427d96 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 20 Feb 2009 10:30:12 +0100 Subject: v4l2-common/v4l2-spec: support/document write-only and button controls From: Hans Verkuil The controls V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET changed their type to button controls (these are unused at the moment, so this is a safe change). The controls V4L2_CID_PAN_RELATIVE, V4L2_CID_TILT_RELATIVE, V4L2_CID_FOCUS_RELATIVE and V4L2_CID_ZOOM_RELATIVE are marked as write-only controls. Priority: normal Signed-off-by: Hans Verkuil CC: Laurent Pinchart --- linux/drivers/media/video/v4l2-common.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index ec81afb19..c2d71816e 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -391,16 +391,16 @@ const char *v4l2_ctrl_get_name(u32 id) switch (id) { /* USER controls */ case V4L2_CID_USER_CLASS: return "User Controls"; + case V4L2_CID_BRIGHTNESS: return "Brightness"; + case V4L2_CID_CONTRAST: return "Contrast"; + case V4L2_CID_SATURATION: return "Saturation"; + case V4L2_CID_HUE: return "Hue"; case V4L2_CID_AUDIO_VOLUME: return "Volume"; - case V4L2_CID_AUDIO_MUTE: return "Mute"; case V4L2_CID_AUDIO_BALANCE: return "Balance"; case V4L2_CID_AUDIO_BASS: return "Bass"; case V4L2_CID_AUDIO_TREBLE: return "Treble"; + case V4L2_CID_AUDIO_MUTE: return "Mute"; case V4L2_CID_AUDIO_LOUDNESS: return "Loudness"; - case V4L2_CID_BRIGHTNESS: return "Brightness"; - case V4L2_CID_CONTRAST: return "Contrast"; - case V4L2_CID_SATURATION: return "Saturation"; - case V4L2_CID_HUE: return "Hue"; case V4L2_CID_BLACK_LEVEL: return "Black Level"; case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic"; case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance"; @@ -500,16 +500,25 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: case V4L2_CID_HUE_AUTO: + case V4L2_CID_CHROMA_AGC: + case V4L2_CID_COLOR_KILLER: case V4L2_CID_MPEG_AUDIO_MUTE: case V4L2_CID_MPEG_VIDEO_MUTE: case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: case V4L2_CID_MPEG_VIDEO_PULLDOWN: case V4L2_CID_EXPOSURE_AUTO_PRIORITY: + case V4L2_CID_FOCUS_AUTO: case V4L2_CID_PRIVACY: qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; min = 0; max = step = 1; break; + case V4L2_CID_PAN_RESET: + case V4L2_CID_TILT_RESET: + qctrl->type = V4L2_CTRL_TYPE_BUTTON; + qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; + min = max = step = def = 0; + break; case V4L2_CID_POWER_LINE_FREQUENCY: case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: case V4L2_CID_MPEG_AUDIO_ENCODING: @@ -558,8 +567,17 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_CONTRAST: case V4L2_CID_SATURATION: case V4L2_CID_HUE: + case V4L2_CID_RED_BALANCE: + case V4L2_CID_BLUE_BALANCE: + case V4L2_CID_GAMMA: qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; break; + case V4L2_CID_PAN_RELATIVE: + case V4L2_CID_TILT_RELATIVE: + case V4L2_CID_FOCUS_RELATIVE: + case V4L2_CID_ZOOM_RELATIVE: + qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; + break; } qctrl->minimum = min; qctrl->maximum = max; @@ -579,6 +597,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) /* USER controls */ case V4L2_CID_USER_CLASS: case V4L2_CID_MPEG_CLASS: + case V4L2_CID_CAMERA_CLASS: return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); case V4L2_CID_AUDIO_VOLUME: return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880); -- cgit v1.2.3 From d649a4d46ae66654680799c6ee8c72cdd610658e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 21 Feb 2009 22:08:41 +0100 Subject: v4l2-common: add v4l2_i2c_subdev_addr() From: Hans Verkuil Add small function to retrieve the i2c address from a v4l2_subdev pointer. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 8ae8dd366..78063b055 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -1049,6 +1049,15 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, } EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev); +/* Return i2c client address of v4l2_subdev. */ +unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return client ? client->addr : I2C_CLIENT_END; +} +EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr); + /* Return a list of I2C tuner addresses to probe. Use only if the tuner addresses are unknown. */ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) -- cgit v1.2.3 From c25f637daca2ca532f5cf0bb6f32decb8308953c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 21 Feb 2009 22:11:31 +0100 Subject: usbvision: convert to v4l2_device/v4l2_subdev. From: Hans Verkuil Priority: normal Signed-off-by: Hans Verkuil --- .../drivers/media/video/usbvision/usbvision-core.c | 2 +- .../drivers/media/video/usbvision/usbvision-i2c.c | 147 ++++++--------------- .../media/video/usbvision/usbvision-video.c | 63 ++++----- linux/drivers/media/video/usbvision/usbvision.h | 8 +- 4 files changed, 75 insertions(+), 145 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c index 440f1b05a..412149bbe 100644 --- a/linux/drivers/media/video/usbvision/usbvision-core.c +++ b/linux/drivers/media/video/usbvision/usbvision-core.c @@ -2654,7 +2654,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) } route.input = mode[channel]; route.output = 0; - call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); + call_all(usbvision, video, s_routing, &route); usbvision_set_audio(usbvision, audio[channel]); return 0; } diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c index 4c74861f4..addc1716e 100644 --- a/linux/drivers/media/video/usbvision/usbvision-i2c.c +++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c @@ -206,72 +206,78 @@ static struct i2c_algorithm usbvision_algo = { }; -/* - * registering functions to load algorithms at runtime - */ -static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) -{ - PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); - PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]"); - - /* register new adapter to i2c module... */ - - adap->algo = &usbvision_algo; - - adap->timeout = 100; /* default values, should */ - adap->retries = 3; /* be replaced by defines */ - - i2c_add_adapter(adap); - - PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name); - - return 0; -} - /* ----------------------------------------------------------------------- */ /* usbvision specific I2C functions */ /* ----------------------------------------------------------------------- */ static struct i2c_adapter i2c_adap_template; -static struct i2c_client i2c_client_template; int usbvision_i2c_register(struct usb_usbvision *usbvision) { + static unsigned short saa711x_addrs[] = { + 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ + 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ + I2C_CLIENT_END }; + memcpy(&usbvision->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); - memcpy(&usbvision->i2c_client, &i2c_client_template, - sizeof(struct i2c_client)); sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), " #%d", usbvision->vdev->num); PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; - i2c_set_adapdata(&usbvision->i2c_adap, usbvision); - i2c_set_clientdata(&usbvision->i2c_client, usbvision); - - usbvision->i2c_client.adapter = &usbvision->i2c_adap; + i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev); if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { printk(KERN_ERR "usbvision_register: can't write reg\n"); return -EBUSY; } -#ifdef CONFIG_MODULES + PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); + PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]"); + + /* register new adapter to i2c module... */ + + usbvision->i2c_adap.algo = &usbvision_algo; + + usbvision->i2c_adap.timeout = 100; /* default values, should */ + usbvision->i2c_adap.retries = 3; /* be replaced by defines */ + + i2c_add_adapter(&usbvision->i2c_adap); + + PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name); + /* Request the load of the i2c modules we need */ switch (usbvision_device_data[usbvision->DevModel].Codec) { case CODEC_SAA7113: - request_module("saa7115"); - break; case CODEC_SAA7111: - request_module("saa7115"); + v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "saa7115", + "saa7115_auto", saa711x_addrs); break; } if (usbvision_device_data[usbvision->DevModel].Tuner == 1) { - request_module("tuner"); + struct v4l2_subdev *sd; + enum v4l2_i2c_tuner_type type; + struct tuner_setup tun_setup; + + sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner", + "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + /* depending on whether we found a demod or not, select + the tuner type. */ + type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; + + sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner", + "tuner", v4l2_i2c_tuner_addrs(type)); + + if (usbvision->tuner_type != -1) { + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = usbvision->tuner_type; + tun_setup.addr = v4l2_i2c_subdev_addr(sd); + call_all(usbvision, tuner, s_type_addr, &tun_setup); + } } -#endif - return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); + return 0; } int usbvision_i2c_unregister(struct usb_usbvision *usbvision) @@ -284,67 +290,6 @@ int usbvision_i2c_unregister(struct usb_usbvision *usbvision) return 0; } -void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, - void *arg) -{ - i2c_clients_command(&usbvision->i2c_adap, cmd, arg); -} - -static int attach_inform(struct i2c_client *client) -{ - struct usb_usbvision *usbvision; - - usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); - - switch (client->addr << 1) { - case 0x42 << 1: - case 0x43 << 1: - case 0x4a << 1: - case 0x4b << 1: - PDEBUG(DBG_I2C,"attach_inform: tda9887 detected."); - break; - case 0x42: - PDEBUG(DBG_I2C,"attach_inform: saa7114 detected."); - break; - case 0x4a: - PDEBUG(DBG_I2C,"attach_inform: saa7113 detected."); - break; - case 0x48: - PDEBUG(DBG_I2C,"attach_inform: saa7111 detected."); - break; - case 0xa0: - PDEBUG(DBG_I2C,"attach_inform: eeprom detected."); - break; - - default: - { - struct tuner_setup tun_setup; - - PDEBUG(DBG_I2C,"attach inform: detected I2C address %x", client->addr << 1); - usbvision->tuner_addr = client->addr; - - if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) { - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = usbvision->tuner_type; - tun_setup.addr = usbvision->tuner_addr; - call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - break; - } - return 0; -} - -static int detach_inform(struct i2c_client *client) -{ - struct usb_usbvision *usbvision; - - usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); - - PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name); - return 0; -} - static int usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr, char *buf, short len) @@ -517,14 +462,6 @@ static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char add static struct i2c_adapter i2c_adap_template = { .owner = THIS_MODULE, .name = "usbvision", - .id = I2C_HW_B_BT848, /* FIXME */ - .client_register = attach_inform, - .client_unregister = detach_inform, - .class = I2C_CLASS_TV_ANALOG, -}; - -static struct i2c_client i2c_client_template = { - .name = "usbvision internal", }; /* diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c index 334c77d91..cfa184d63 100644 --- a/linux/drivers/media/video/usbvision/usbvision-video.c +++ b/linux/drivers/media/video/usbvision/usbvision-video.c @@ -212,7 +212,7 @@ static ssize_t show_hue(struct device *cd, ctrl.id = V4L2_CID_HUE; ctrl.value = 0; if(usbvision->user) - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + call_all(usbvision, core, g_ctrl, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); @@ -227,7 +227,7 @@ static ssize_t show_contrast(struct device *cd, ctrl.id = V4L2_CID_CONTRAST; ctrl.value = 0; if(usbvision->user) - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + call_all(usbvision, core, g_ctrl, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); @@ -242,7 +242,7 @@ static ssize_t show_brightness(struct device *cd, ctrl.id = V4L2_CID_BRIGHTNESS; ctrl.value = 0; if(usbvision->user) - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + call_all(usbvision, core, g_ctrl, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); @@ -257,7 +257,7 @@ static ssize_t show_saturation(struct device *cd, ctrl.id = V4L2_CID_SATURATION; ctrl.value = 0; if(usbvision->user) - call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + call_all(usbvision, core, g_ctrl, &ctrl); return sprintf(buf, "%d\n", ctrl.value); } static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); @@ -622,8 +622,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) usbvision->tvnormId=*id; mutex_lock(&usbvision->lock); - call_i2c_clients(usbvision, VIDIOC_S_STD, - &usbvision->tvnormId); + call_all(usbvision, tuner, s_std, usbvision->tvnormId); mutex_unlock(&usbvision->lock); /* propagate the change to the decoder */ usbvision_muxsel(usbvision, usbvision->ctl_input); @@ -645,7 +644,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, strcpy(vt->name, "Television"); } /* Let clients fill in the remainder of this struct */ - call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt); + call_all(usbvision, tuner, g_tuner, vt); return 0; } @@ -659,7 +658,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, if (!usbvision->have_tuner || vt->index) return -EINVAL; /* let clients handle this */ - call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); + call_all(usbvision, tuner, s_tuner, vt); return 0; } @@ -690,7 +689,7 @@ static int vidioc_s_frequency (struct file *file, void *priv, return -EINVAL; usbvision->freq = freq->frequency; - call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq); + call_all(usbvision, tuner, s_frequency, freq); return 0; } @@ -728,7 +727,7 @@ static int vidioc_queryctrl (struct file *file, void *priv, memset(ctrl,0,sizeof(*ctrl)); ctrl->id=id; - call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl); + call_all(usbvision, core, queryctrl, ctrl); if (!ctrl->type) return -EINVAL; @@ -740,7 +739,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { struct usb_usbvision *usbvision = video_drvdata(file); - call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); + call_all(usbvision, core, g_ctrl, ctrl); return 0; } @@ -749,7 +748,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { struct usb_usbvision *usbvision = video_drvdata(file); - call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); + call_all(usbvision, core, s_ctrl, ctrl); return 0; } @@ -900,10 +899,9 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct usb_usbvision *usbvision = video_drvdata(file); - int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; usbvision->streaming = Stream_On; - call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); + call_all(usbvision, video, s_stream, 1); return 0; } @@ -912,7 +910,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { struct usb_usbvision *usbvision = video_drvdata(file); - int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -920,7 +917,7 @@ static int vidioc_streamoff(struct file *file, if(usbvision->streaming == Stream_On) { usbvision_stream_interrupt(usbvision); /* Stop all video streamings */ - call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); + call_all(usbvision, video, s_stream, 0); } usbvision_empty_framequeues(usbvision); @@ -1043,7 +1040,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, if(usbvision->streaming != Stream_On) { /* no stream is running, make it running ! */ usbvision->streaming = Stream_On; - call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL); + call_all(usbvision, video, s_stream, 1); } /* Then, enqueue as many frames as possible @@ -1214,7 +1211,7 @@ static int usbvision_radio_open(struct file *file) // If so far no errors then we shall start the radio usbvision->radio = 1; - call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); + call_all(usbvision, tuner, s_radio); usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); usbvision->user++; } @@ -1427,7 +1424,7 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, } *vdev = *vdev_template; // vdev->minor = -1; - vdev->parent = &usb_dev->dev; + vdev->v4l2_dev = &usbvision->v4l2_dev; snprintf(vdev->name, sizeof(vdev->name), "%s", name); video_set_drvdata(vdev, usbvision); return vdev; @@ -1548,33 +1545,30 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) { struct usb_usbvision *usbvision; - if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == - NULL) { - goto err_exit; - } + usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL); + if (usbvision == NULL) + return NULL; usbvision->dev = dev; + if (v4l2_device_register(&dev->dev, &usbvision->v4l2_dev)) + goto err_free; mutex_init(&usbvision->lock); /* available */ // prepare control urb for control messages during interrupts usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); - if (usbvision->ctrlUrb == NULL) { - goto err_exit; - } + if (usbvision->ctrlUrb == NULL) + goto err_unreg; init_waitqueue_head(&usbvision->ctrlUrb_wq); usbvision_init_powerOffTimer(usbvision); return usbvision; -err_exit: - if (usbvision && usbvision->ctrlUrb) { - usb_free_urb(usbvision->ctrlUrb); - } - if (usbvision) { - kfree(usbvision); - } +err_unreg: + v4l2_device_unregister(&usbvision->v4l2_dev); +err_free: + kfree(usbvision); return NULL; } @@ -1604,6 +1598,7 @@ static void usbvision_release(struct usb_usbvision *usbvision) usb_free_urb(usbvision->ctrlUrb); } + v4l2_device_unregister(&usbvision->v4l2_dev); kfree(usbvision); PDEBUG(DBG_PROBE, "success"); @@ -1739,8 +1734,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->tuner_type = usbvision_device_data[model].TunerType; } - usbvision->tuner_addr = ADDR_UNSET; - usbvision->DevModel = model; usbvision->remove_pending = 0; usbvision->iface = ifnum; diff --git a/linux/drivers/media/video/usbvision/usbvision.h b/linux/drivers/media/video/usbvision/usbvision.h index 590ff1e19..dc86c2139 100644 --- a/linux/drivers/media/video/usbvision/usbvision.h +++ b/linux/drivers/media/video/usbvision/usbvision.h @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include "compat.h" @@ -358,13 +358,13 @@ extern struct usbvision_device_data_st usbvision_device_data[]; extern struct usb_device_id usbvision_table[]; struct usb_usbvision { + struct v4l2_device v4l2_dev; struct video_device *vdev; /* Video Device */ struct video_device *rdev; /* Radio Device */ struct video_device *vbi; /* VBI Device */ /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; struct urb *ctrlUrb; unsigned char ctrlUrbBuffer[8]; @@ -375,7 +375,6 @@ struct usb_usbvision { /* configuration part */ int have_tuner; int tuner_type; - int tuner_addr; int bridgeType; // NT1003, NT1004, NT1005 int radio; int video_inputs; // # of inputs @@ -465,6 +464,8 @@ struct usb_usbvision { int ComprBlockTypes[4]; }; +#define call_all(usbvision, o, f, args...) \ + v4l2_device_call_all(&usbvision->v4l2_dev, 0, o, f, ##args) /* --------------------------------------------------------------- */ /* defined in usbvision-i2c.c */ @@ -476,7 +477,6 @@ struct usb_usbvision { /* ----------------------------------------------------------------------- */ int usbvision_i2c_register(struct usb_usbvision *usbvision); int usbvision_i2c_unregister(struct usb_usbvision *usbvision); -void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); /* defined in usbvision-core.c */ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); -- cgit v1.2.3 From ceb38ab7b287651e30d049e86e6469d4bcc3ea3b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 21 Feb 2009 22:47:24 +0100 Subject: v4l2-common: remove v4l2_ctrl_query_fill_std From: Hans Verkuil The v4l2_ctrl_query_fill_std() function wasn't one the best idea I ever had. It doesn't add anything valuable that cannot be expressed equally well with v4l2_ctrl_query_fill and only adds overhead. Replace it with v4l2_ctrl_query_fill() everywhere it is used and remove it from v4l2_common.c. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/cx18/cx18-av-core.c | 7 +- linux/drivers/media/video/cx2341x.c | 108 ++++++++++++---- linux/drivers/media/video/cx25840/cx25840-core.c | 7 +- linux/drivers/media/video/msp3400-driver.c | 26 ++-- linux/drivers/media/video/saa7115.c | 4 +- linux/drivers/media/video/saa7134/saa6752hs.c | 12 +- .../drivers/media/video/saa7134/saa7134-empress.c | 2 +- linux/drivers/media/video/tda7432.c | 6 +- linux/drivers/media/video/tda9875.c | 3 +- linux/drivers/media/video/tvaudio.c | 17 ++- linux/drivers/media/video/tvp514x.c | 5 +- linux/drivers/media/video/v4l2-common.c | 142 --------------------- 12 files changed, 141 insertions(+), 198 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c index a3bd2c95f..fc576cf1a 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.c +++ b/linux/drivers/media/video/cx18/cx18-av-core.c @@ -788,10 +788,12 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg) switch (qc->id) { case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); case V4L2_CID_CONTRAST: case V4L2_CID_SATURATION: + return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); case V4L2_CID_HUE: - return v4l2_ctrl_query_fill_std(qc); + return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); default: break; } @@ -801,10 +803,11 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg) return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, state->default_volume); case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); default: return -EINVAL; } diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c index 01c4d2d02..2cf0c5fee 100644 --- a/linux/drivers/media/video/cx2341x.c +++ b/linux/drivers/media/video/cx2341x.c @@ -501,6 +501,29 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, int err; switch (qctrl->id) { + case V4L2_CID_MPEG_STREAM_TYPE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS, + V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1, + V4L2_MPEG_STREAM_TYPE_MPEG2_PS); + + case V4L2_CID_MPEG_STREAM_VBI_FMT: + if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_VBI_FMT_NONE, + V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, + V4L2_MPEG_STREAM_VBI_FMT_NONE); + return cx2341x_ctrl_query_fill(qctrl, + V4L2_MPEG_STREAM_VBI_FMT_NONE, + V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, + default_params.stream_vbi_fmt); + + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1, + V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); + case V4L2_CID_MPEG_AUDIO_ENCODING: if (params->capabilities & CX2341X_CAP_HAS_AC3) { /* @@ -532,9 +555,36 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: - return -EINVAL; + case V4L2_CID_MPEG_AUDIO_MODE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_MODE_STEREO, + V4L2_MPEG_AUDIO_MODE_MONO, 1, + V4L2_MPEG_AUDIO_MODE_STEREO); + + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1, + V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); + if (err == 0 && + params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return err; + + case V4L2_CID_MPEG_AUDIO_EMPHASIS: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_EMPHASIS_NONE, + V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1, + V4L2_MPEG_AUDIO_EMPHASIS_NONE); + + case V4L2_CID_MPEG_AUDIO_CRC: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_CRC_NONE, + V4L2_MPEG_AUDIO_CRC_CRC16, 1, + V4L2_MPEG_AUDIO_CRC_NONE); + + case V4L2_CID_MPEG_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: err = v4l2_ctrl_query_fill(qctrl, @@ -551,13 +601,6 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; return 0; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && - params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return err; - case V4L2_CID_MPEG_VIDEO_ENCODING: /* this setting is read-only for the cx2341x since the V4L2_CID_MPEG_STREAM_TYPE really determines the @@ -570,32 +613,51 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; return err; + case V4L2_CID_MPEG_VIDEO_ASPECT: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ASPECT_1x1, + V4L2_MPEG_VIDEO_ASPECT_221x100, 1, + V4L2_MPEG_VIDEO_ASPECT_4x3); + + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2); + + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, + params->is_50hz ? 12 : 15); + + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - err = v4l2_ctrl_query_fill_std(qctrl); + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; + case V4L2_CID_MPEG_VIDEO_BITRATE: + return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - err = v4l2_ctrl_query_fill_std(qctrl); + err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; - case V4L2_CID_MPEG_STREAM_VBI_FMT: - if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) - return v4l2_ctrl_query_fill_std(qctrl); - return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_STREAM_VBI_FMT_NONE, - V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, - default_params.stream_vbi_fmt); + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: + return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, - params->is_50hz ? 12 : 15); + case V4L2_CID_MPEG_VIDEO_MUTE: + return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); + + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ + return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); /* CX23415/6 specific */ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: @@ -697,7 +759,7 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, default_params.stream_insert_nav_packets); default: - return v4l2_ctrl_query_fill_std(qctrl); + return -EINVAL; } } diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index d70dcd028..921cc96fc 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -1224,10 +1224,12 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) switch (qc->id) { case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); case V4L2_CID_CONTRAST: case V4L2_CID_SATURATION: + return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); case V4L2_CID_HUE: - return v4l2_ctrl_query_fill_std(qc); + return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); default: break; } @@ -1239,10 +1241,11 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, state->default_volume); case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); default: return -EINVAL; } diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index 053f168bf..61b54317f 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -718,22 +718,24 @@ static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) struct msp_state *state = to_state(sd); switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill_std(qc); - default: - break; + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); + default: + break; } if (!state->has_sound_processing) return -EINVAL; switch (qc->id) { - case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); - default: - return -EINVAL; + case V4L2_CID_AUDIO_LOUDNESS: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); + default: + return -EINVAL; } return 0; } diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c index 9fbb93775..a870ae5d2 100644 --- a/linux/drivers/media/video/saa7115.c +++ b/linux/drivers/media/video/saa7115.c @@ -1207,10 +1207,12 @@ static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) { switch (qc->id) { case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); case V4L2_CID_CONTRAST: case V4L2_CID_SATURATION: + return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); case V4L2_CID_HUE: - return v4l2_ctrl_query_fill_std(qc); + return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); default: return -EINVAL; } diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c index 2e2871de1..3af36d929 100644 --- a/linux/drivers/media/video/saa7134/saa6752hs.c +++ b/linux/drivers/media/video/saa7134/saa6752hs.c @@ -599,7 +599,7 @@ static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc V4L2_MPEG_VIDEO_ASPECT_4x3); case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - err = v4l2_ctrl_query_fill_std(qctrl); + err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); if (err == 0 && params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) @@ -613,12 +613,20 @@ static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc V4L2_MPEG_STREAM_TYPE_MPEG2_TS); case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); case V4L2_CID_MPEG_VIDEO_BITRATE: + return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); case V4L2_CID_MPEG_STREAM_PID_PMT: + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16); case V4L2_CID_MPEG_STREAM_PID_AUDIO: + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260); case V4L2_CID_MPEG_STREAM_PID_VIDEO: + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256); case V4L2_CID_MPEG_STREAM_PID_PCR: - return v4l2_ctrl_query_fill_std(qctrl); + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259); default: break; diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c index 813f5f88d..609342128 100644 --- a/linux/drivers/media/video/saa7134/saa7134-empress.c +++ b/linux/drivers/media/video/saa7134/saa7134-empress.c @@ -390,7 +390,7 @@ static int empress_queryctrl(struct file *file, void *priv, if (c->id == 0) return -EINVAL; if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS) - return v4l2_ctrl_query_fill_std(c); + return v4l2_ctrl_query_fill(c, 0, 0, 0, 0); if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) return saa7134_queryctrl(file, priv, c); return saa_call_empress(dev, core, queryctrl, c); diff --git a/linux/drivers/media/video/tda7432.c b/linux/drivers/media/video/tda7432.c index 30f6f8a38..104fc4246 100644 --- a/linux/drivers/media/video/tda7432.c +++ b/linux/drivers/media/video/tda7432.c @@ -422,12 +422,14 @@ static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) { switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); } return -EINVAL; } diff --git a/linux/drivers/media/video/tda9875.c b/linux/drivers/media/video/tda9875.c index 892d25a40..938bafbbd 100644 --- a/linux/drivers/media/video/tda9875.c +++ b/linux/drivers/media/video/tda9875.c @@ -327,9 +327,10 @@ static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) { switch (qc->id) { case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); } return -EINVAL; } diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c index 3ca242af5..e8a6893ff 100644 --- a/linux/drivers/media/video/tvaudio.c +++ b/linux/drivers/media/video/tvaudio.c @@ -1644,21 +1644,24 @@ static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) switch (qc->id) { case V4L2_CID_AUDIO_MUTE: - break; + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); case V4L2_CID_AUDIO_VOLUME: + if (desc->flags & CHIP_HAS_VOLUME) + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); + break; case V4L2_CID_AUDIO_BALANCE: - if (!(desc->flags & CHIP_HAS_VOLUME)) - return -EINVAL; + if (desc->flags & CHIP_HAS_VOLUME) + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); break; case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - if (!(desc->flags & CHIP_HAS_BASSTREBLE)) - return -EINVAL; + if (desc->flags & CHIP_HAS_BASSTREBLE) + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); break; default: - return -EINVAL; + break; } - return v4l2_ctrl_query_fill_std(qc); + return -EINVAL; } static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt) diff --git a/linux/drivers/media/video/tvp514x.c b/linux/drivers/media/video/tvp514x.c index 5f4cbc2b2..c20af91ff 100644 --- a/linux/drivers/media/video/tvp514x.c +++ b/linux/drivers/media/video/tvp514x.c @@ -719,10 +719,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl) switch (qctrl->id) { case V4L2_CID_BRIGHTNESS: - /* Brightness supported is same as standard one (0-255), - * so make use of standard API provided. + /* Brightness supported is (0-255), */ - err = v4l2_ctrl_query_fill_std(qctrl); + err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); break; case V4L2_CID_CONTRAST: case V4L2_CID_SATURATION: diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 8ae8dd366..963277e93 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -561,148 +561,6 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste } EXPORT_SYMBOL(v4l2_ctrl_query_fill); -/* Fill in a struct v4l2_queryctrl with standard values based on - the control ID. */ -int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) -{ - switch (qctrl->id) { - /* USER controls */ - case V4L2_CID_USER_CLASS: - case V4L2_CID_MPEG_CLASS: - return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880); - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_LOUDNESS: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768); - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0); - - /* MPEG controls */ - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1, - V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); - case V4L2_CID_MPEG_AUDIO_ENCODING: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_ENCODING_LAYER_1, - V4L2_MPEG_AUDIO_ENCODING_AC3, 1, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2); - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_L1_BITRATE_32K, - V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1, - V4L2_MPEG_AUDIO_L1_BITRATE_256K); - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_L2_BITRATE_32K, - V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, - V4L2_MPEG_AUDIO_L2_BITRATE_224K); - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_L3_BITRATE_32K, - V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1, - V4L2_MPEG_AUDIO_L3_BITRATE_192K); - case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: - return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000); - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_AC3_BITRATE_32K, - V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1, - V4L2_MPEG_AUDIO_AC3_BITRATE_384K); - case V4L2_CID_MPEG_AUDIO_MODE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_MODE_STEREO, - V4L2_MPEG_AUDIO_MODE_MONO, 1, - V4L2_MPEG_AUDIO_MODE_STEREO); - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1, - V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); - case V4L2_CID_MPEG_AUDIO_EMPHASIS: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_EMPHASIS_NONE, - V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1, - V4L2_MPEG_AUDIO_EMPHASIS_NONE); - case V4L2_CID_MPEG_AUDIO_CRC: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_AUDIO_CRC_NONE, - V4L2_MPEG_AUDIO_CRC_CRC16, 1, - V4L2_MPEG_AUDIO_CRC_NONE); - case V4L2_CID_MPEG_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); - case V4L2_CID_MPEG_VIDEO_ENCODING: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_ENCODING_MPEG_1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2); - case V4L2_CID_MPEG_VIDEO_ASPECT: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_ASPECT_1x1, - V4L2_MPEG_VIDEO_ASPECT_221x100, 1, - V4L2_MPEG_VIDEO_ASPECT_4x3); - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12); - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); - case V4L2_CID_MPEG_VIDEO_PULLDOWN: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, - V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: - return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); - case V4L2_CID_MPEG_VIDEO_MUTE: - return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ - return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); - case V4L2_CID_MPEG_STREAM_TYPE: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_STREAM_TYPE_MPEG2_PS, - V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1, - V4L2_MPEG_STREAM_TYPE_MPEG2_PS); - case V4L2_CID_MPEG_STREAM_PID_PMT: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16); - case V4L2_CID_MPEG_STREAM_PID_AUDIO: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260); - case V4L2_CID_MPEG_STREAM_PID_VIDEO: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256); - case V4L2_CID_MPEG_STREAM_PID_PCR: - return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259); - case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: - return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); - case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: - return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); - case V4L2_CID_MPEG_STREAM_VBI_FMT: - return v4l2_ctrl_query_fill(qctrl, - V4L2_MPEG_STREAM_VBI_FMT_NONE, - V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, - V4L2_MPEG_STREAM_VBI_FMT_NONE); - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); - /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and the menu. The qctrl pointer may be NULL, in which case it is ignored. If menu_items is NULL, then the menu items are retrieved using -- cgit v1.2.3 From 9fff09d63089bb9963bac49d563e934a54d2ccb6 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: soc-camera: add data signal polarity flags to drivers From: Guennadi Liakhovetski All soc-camera camera and host drivers must specify supported data signal polarity, after all drivers are fixed, we'll add a suitable test to soc_camera_bus_param_compatible(). Signed-off-by: Guennadi Liakhovetski --- arch/sh/boards/board-ap325rxa.c | 3 ++- arch/sh/boards/mach-migor/setup.c | 5 +++-- drivers/media/video/mt9m001.c | 2 +- drivers/media/video/mt9m111.c | 2 +- drivers/media/video/mt9v022.c | 2 +- drivers/media/video/ov772x.c | 2 +- drivers/media/video/pxa_camera.c | 1 + 7 files changed, 10 insertions(+), 7 deletions(-) --- linux/drivers/media/video/mt9m001.c | 2 +- linux/drivers/media/video/mt9m111.c | 2 +- linux/drivers/media/video/mt9v022.c | 2 +- linux/drivers/media/video/ov772x.c | 2 +- linux/drivers/media/video/pxa_camera.c | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index 3d8e6ed8d..c2e52100a 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -276,7 +276,7 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) /* MT9M001 has all capture_format parameters fixed */ unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_MASTER; + SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER; if (bus_switch_possible(mt9m001)) flags |= SOCAM_DATAWIDTH_8; diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c index cdf3f38e2..b2989c0f2 100644 --- a/linux/drivers/media/video/mt9m111.c +++ b/linux/drivers/media/video/mt9m111.c @@ -420,7 +420,7 @@ static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) struct soc_camera_link *icl = mt9m111->client->dev.platform_data; unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | - SOCAM_DATAWIDTH_8; + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; return soc_camera_apply_sensor_flags(icl, flags); } diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c index 9601884ca..59efb8ff0 100644 --- a/linux/drivers/media/video/mt9v022.c +++ b/linux/drivers/media/video/mt9v022.c @@ -336,7 +336,7 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | - SOCAM_MASTER | SOCAM_SLAVE | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_SLAVE | width_flag; } diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c index ce389cacf..74458378a 100644 --- a/linux/drivers/media/video/ov772x.c +++ b/linux/drivers/media/video/ov772x.c @@ -718,7 +718,7 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) struct soc_camera_link *icl = priv->client->dev.platform_data; unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | - priv->info->buswidth; + SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; return soc_camera_apply_sensor_flags(icl, flags); } diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c index b6a34ba18..dd524b3c6 100644 --- a/linux/drivers/media/video/pxa_camera.c +++ b/linux/drivers/media/video/pxa_camera.c @@ -888,6 +888,7 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, SOCAM_HSYNC_ACTIVE_LOW | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING; -- cgit v1.2.3 From 20489b399dff421863ee89585f32b960bf7b420e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: ov772x: move configuration from start_capture() to set_fmt() From: Kuninori Morimoto soc_camera framework requires, that camera configuration is performed in set_fmt, and start_capture and stop_capture only turn the camera on/off. This patch modifies ov772x to comply to this requirement. Signed-off-by: Kuninori Morimoto Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/ov772x.c | 125 +++++++++++++++++++++--------------------- 1 files changed, 62 insertions(+), 63 deletions(-) --- linux/drivers/media/video/ov772x.c | 125 ++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 63 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c index 74458378a..881463a0b 100644 --- a/linux/drivers/media/video/ov772x.c +++ b/linux/drivers/media/video/ov772x.c @@ -500,9 +500,8 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = { /* * color format list */ -#define T_YUYV 0 static const struct ov772x_color_format ov772x_cfmts[] = { - [T_YUYV] = { + { SETFOURCC(YUYV), .regs = ov772x_YYUV_regs, }, @@ -635,74 +634,20 @@ static int ov772x_release(struct soc_camera_device *icd) static int ov772x_start_capture(struct soc_camera_device *icd) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); - int ret; - - if (!priv->win) - priv->win = &ov772x_win_vga; - if (!priv->fmt) - priv->fmt = &ov772x_cfmts[T_YUYV]; - - /* - * reset hardware - */ - ov772x_reset(priv->client); - - /* - * set color format - */ - ret = ov772x_write_array(priv->client, priv->fmt->regs); - if (ret < 0) - goto start_end; - - /* - * set size format - */ - ret = ov772x_write_array(priv->client, priv->win->regs); - if (ret < 0) - goto start_end; - - /* - * set COM7 bit ( QVGA or VGA ) - */ - ret = ov772x_mask_set(priv->client, - COM7, SLCT_MASK, priv->win->com7_bit); - if (ret < 0) - goto start_end; - /* - * set UV setting - */ - if (priv->fmt->option & OP_UV) { - ret = ov772x_mask_set(priv->client, - DSP_CTRL3, UV_MASK, UV_ON); - if (ret < 0) - goto start_end; - } - - /* - * set SWAP setting - */ - if (priv->fmt->option & OP_SWAP_RGB) { - ret = ov772x_mask_set(priv->client, - COM3, SWAP_MASK, SWAP_RGB); - if (ret < 0) - goto start_end; + if (!priv->win || !priv->fmt) { + dev_err(&icd->dev, "norm or win select error\n"); + return -EPERM; } dev_dbg(&icd->dev, "format %s, win %s\n", priv->fmt->name, priv->win->name); -start_end: - priv->fmt = NULL; - priv->win = NULL; - - return ret; + return 0; } static int ov772x_stop_capture(struct soc_camera_device *icd) { - struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); - ov772x_reset(priv->client); return 0; } @@ -787,7 +732,6 @@ ov772x_select_win(u32 width, u32 height) return win; } - static int ov772x_set_fmt(struct soc_camera_device *icd, __u32 pixfmt, struct v4l2_rect *rect) @@ -803,16 +747,72 @@ static int ov772x_set_fmt(struct soc_camera_device *icd, for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { if (pixfmt == ov772x_cfmts[i].fourcc) { priv->fmt = ov772x_cfmts + i; - ret = 0; break; } } + if (!priv->fmt) + goto ov772x_set_fmt_error; /* * select win */ priv->win = ov772x_select_win(rect->width, rect->height); + /* + * reset hardware + */ + ov772x_reset(priv->client); + + /* + * set color format + */ + ret = ov772x_write_array(priv->client, priv->fmt->regs); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set size format + */ + ret = ov772x_write_array(priv->client, priv->win->regs); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set COM7 bit ( QVGA or VGA ) + */ + ret = ov772x_mask_set(priv->client, + COM7, SLCT_MASK, priv->win->com7_bit); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set UV setting + */ + if (priv->fmt->option & OP_UV) { + ret = ov772x_mask_set(priv->client, + DSP_CTRL3, UV_MASK, UV_ON); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + /* + * set SWAP setting + */ + if (priv->fmt->option & OP_SWAP_RGB) { + ret = ov772x_mask_set(priv->client, + COM3, SWAP_MASK, SWAP_RGB); + if (ret < 0) + goto ov772x_set_fmt_error; + } + + return ret; + +ov772x_set_fmt_error: + + ov772x_reset(priv->client); + priv->win = NULL; + priv->fmt = NULL; + return ret; } @@ -889,7 +889,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd) i2c_smbus_read_byte_data(priv->client, MIDH), i2c_smbus_read_byte_data(priv->client, MIDL)); - return soc_camera_video_start(icd); } -- cgit v1.2.3 From 7c67818bb02d27076080edb44bbcb661e45fd2a5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: ov772x: setting method to register is changed. From: Kuninori Morimoto Color format regs array had been used, but it was not easy to understand what to want to do, and additional bit became complex. This patch modify this problem. Signed-off-by: Kuninori Morimoto Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/ov772x.c | 121 +++++++++++++++++------------------------- 1 files changed, 48 insertions(+), 73 deletions(-) --- linux/drivers/media/video/ov772x.c | 121 +++++++++++++++---------------------- 1 file changed, 48 insertions(+), 73 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c index 881463a0b..211376a41 100644 --- a/linux/drivers/media/video/ov772x.c +++ b/linux/drivers/media/video/ov772x.c @@ -271,11 +271,13 @@ #define SLCT_QVGA 0x40 /* 1 : QVGA */ #define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */ /* RGB output format control */ +#define FMT_MASK 0x0c /* Mask of color format */ #define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */ #define FMT_RGB565 0x04 /* 01 : RGB 565 */ #define FMT_RGB555 0x08 /* 10 : RGB 555 */ #define FMT_RGB444 0x0c /* 11 : RGB 444 */ /* Output format control */ +#define OFMT_MASK 0x03 /* Mask of output format */ #define OFMT_YUV 0x00 /* 00 : YUV */ #define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */ #define OFMT_RGB 0x02 /* 10 : RGB */ @@ -299,7 +301,7 @@ #define GAIN_2x 0x00 /* 000 : 2x */ #define GAIN_4x 0x10 /* 001 : 4x */ #define GAIN_8x 0x20 /* 010 : 8x */ -#define GAIN_16x 0x30 /* 011 : 16x */ +#define GAIN_16x 0x30 /* 011 : 16x */ #define GAIN_32x 0x40 /* 100 : 32x */ #define GAIN_64x 0x50 /* 101 : 64x */ #define GAIN_128x 0x60 /* 110 : 128x */ @@ -355,13 +357,6 @@ #define VOSZ_VGA 0xF0 #define VOSZ_QVGA 0x78 -/* - * bit configure (32 bit) - * this is used in struct ov772x_color_format :: option - */ -#define OP_UV 0x00000001 -#define OP_SWAP_RGB 0x00000002 - /* * ID */ @@ -380,8 +375,9 @@ struct regval_list { struct ov772x_color_format { char *name; __u32 fourcc; - const struct regval_list *regs; - unsigned int option; + u8 dsp3; + u8 com3; + u8 com7; }; struct ov772x_win_size { @@ -403,34 +399,6 @@ struct ov772x_priv { #define ENDMARKER { 0xff, 0xff } -/* - * register setting for color format - */ -static const struct regval_list ov772x_RGB555_regs[] = { - { COM3, 0x00 }, - { COM7, FMT_RGB555 | OFMT_RGB }, - ENDMARKER, -}; - -static const struct regval_list ov772x_RGB565_regs[] = { - { COM3, 0x00 }, - { COM7, FMT_RGB565 | OFMT_RGB }, - ENDMARKER, -}; - -static const struct regval_list ov772x_YYUV_regs[] = { - { COM3, SWAP_YUV }, - { COM7, OFMT_YUV }, - ENDMARKER, -}; - -static const struct regval_list ov772x_UVYY_regs[] = { - { COM3, 0x00 }, - { COM7, OFMT_YUV }, - ENDMARKER, -}; - - /* * register setting for window size */ @@ -503,34 +471,45 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = { static const struct ov772x_color_format ov772x_cfmts[] = { { SETFOURCC(YUYV), - .regs = ov772x_YYUV_regs, + .dsp3 = 0x0, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, }, { SETFOURCC(YVYU), - .regs = ov772x_YYUV_regs, - .option = OP_UV, + .dsp3 = UV_ON, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, }, { SETFOURCC(UYVY), - .regs = ov772x_UVYY_regs, + .dsp3 = 0x0, + .com3 = 0x0, + .com7 = OFMT_YUV, }, { SETFOURCC(RGB555), - .regs = ov772x_RGB555_regs, - .option = OP_SWAP_RGB, + .dsp3 = 0x0, + .com3 = SWAP_RGB, + .com7 = FMT_RGB555 | OFMT_RGB, }, { SETFOURCC(RGB555X), - .regs = ov772x_RGB555_regs, + .dsp3 = 0x0, + .com3 = 0x0, + .com7 = FMT_RGB555 | OFMT_RGB, }, { SETFOURCC(RGB565), - .regs = ov772x_RGB565_regs, - .option = OP_SWAP_RGB, + .dsp3 = 0x0, + .com3 = SWAP_RGB, + .com7 = FMT_RGB565 | OFMT_RGB, }, { SETFOURCC(RGB565X), - .regs = ov772x_RGB565_regs, + .dsp3 = 0x0, + .com3 = 0x0, + .com7 = FMT_RGB565 | OFMT_RGB, }, }; @@ -738,6 +717,7 @@ static int ov772x_set_fmt(struct soc_camera_device *icd, { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); int ret = -EINVAL; + u8 val; int i; /* @@ -763,13 +743,6 @@ static int ov772x_set_fmt(struct soc_camera_device *icd, */ ov772x_reset(priv->client); - /* - * set color format - */ - ret = ov772x_write_array(priv->client, priv->fmt->regs); - if (ret < 0) - goto ov772x_set_fmt_error; - /* * set size format */ @@ -778,32 +751,34 @@ static int ov772x_set_fmt(struct soc_camera_device *icd, goto ov772x_set_fmt_error; /* - * set COM7 bit ( QVGA or VGA ) + * set DSP_CTRL3 */ - ret = ov772x_mask_set(priv->client, - COM7, SLCT_MASK, priv->win->com7_bit); - if (ret < 0) - goto ov772x_set_fmt_error; - - /* - * set UV setting - */ - if (priv->fmt->option & OP_UV) { + val = priv->fmt->dsp3; + if (val) { ret = ov772x_mask_set(priv->client, - DSP_CTRL3, UV_MASK, UV_ON); + DSP_CTRL3, UV_MASK, val); if (ret < 0) goto ov772x_set_fmt_error; } /* - * set SWAP setting + * set COM3 */ - if (priv->fmt->option & OP_SWAP_RGB) { - ret = ov772x_mask_set(priv->client, - COM3, SWAP_MASK, SWAP_RGB); - if (ret < 0) - goto ov772x_set_fmt_error; - } + val = priv->fmt->com3; + ret = ov772x_mask_set(priv->client, + COM3, SWAP_MASK, val); + if (ret < 0) + goto ov772x_set_fmt_error; + + /* + * set COM7 + */ + val = priv->win->com7_bit | priv->fmt->com7; + ret = ov772x_mask_set(priv->client, + COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK), + val); + if (ret < 0) + goto ov772x_set_fmt_error; return ret; -- cgit v1.2.3 From 9f4da9c7feb71ee575960553c4ad10555be64229 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: ov772x: bit mask operation fix on ov772x_mask_set. From: Kuninori Morimoto Signed-off-by: Kuninori Morimoto Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/ov772x.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) --- linux/drivers/media/video/ov772x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c index 211376a41..6e7cfeb18 100644 --- a/linux/drivers/media/video/ov772x.c +++ b/linux/drivers/media/video/ov772x.c @@ -565,8 +565,11 @@ static int ov772x_mask_set(struct i2c_client *client, u8 set) { s32 val = i2c_smbus_read_byte_data(client, command); + if (val < 0) + return val; + val &= ~mask; - val |= set; + val |= set & mask; return i2c_smbus_write_byte_data(client, command, val); } -- cgit v1.2.3 From 7c7069267de14d7c83c611220087cdddd8210604 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: ov772x: Add image flip support From: Kuninori Morimoto o ov772x_camera_info :: flags supports default image flip. o V4L2_CID_VFLIP/HFLIP supports image flip for user side. Thank Magnus for advice. Signed-off-by: Kuninori Morimoto Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/ov772x.c | 88 ++++++++++++++++++++++++++++++++++++++++-- include/media/ov772x.h | 5 ++ 2 files changed, 89 insertions(+), 4 deletions(-) --- linux/drivers/media/video/ov772x.c | 88 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c index 6e7cfeb18..2f3313524 100644 --- a/linux/drivers/media/video/ov772x.c +++ b/linux/drivers/media/video/ov772x.c @@ -217,10 +217,11 @@ #define OCAP_4x 0x03 /* 4x */ /* COM3 */ -#define SWAP_MASK 0x38 +#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML) +#define IMG_MASK (VFLIP_IMG | HFLIP_IMG) -#define VFIMG_ON_OFF 0x80 /* Vertical flip image ON/OFF selection */ -#define HMIMG_ON_OFF 0x40 /* Horizontal mirror image ON/OFF selection */ +#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */ +#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */ #define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */ #define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */ #define SWAP_ML 0x08 /* Swap output MSB/LSB */ @@ -395,6 +396,8 @@ struct ov772x_priv { const struct ov772x_color_format *fmt; const struct ov772x_win_size *win; int model; + unsigned int flag_vflip:1; + unsigned int flag_hflip:1; }; #define ENDMARKER { 0xff, 0xff } @@ -540,6 +543,27 @@ static const struct ov772x_win_size ov772x_win_qvga = { .regs = ov772x_qvga_regs, }; +static const struct v4l2_queryctrl ov772x_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, +}; + /* * general function @@ -650,6 +674,49 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) return soc_camera_apply_sensor_flags(icl, flags); } +static int ov772x_get_control(struct soc_camera_device *icd, + struct v4l2_control *ctrl) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + ctrl->value = priv->flag_vflip; + break; + case V4L2_CID_HFLIP: + ctrl->value = priv->flag_hflip; + break; + } + return 0; +} + +static int ov772x_set_control(struct soc_camera_device *icd, + struct v4l2_control *ctrl) +{ + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret = 0; + u8 val; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + val = ctrl->value ? VFLIP_IMG : 0x00; + priv->flag_vflip = ctrl->value; + if (priv->info->flags & OV772X_FLAG_VFLIP) + val ^= VFLIP_IMG; + ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val); + break; + case V4L2_CID_HFLIP: + val = ctrl->value ? HFLIP_IMG : 0x00; + priv->flag_hflip = ctrl->value; + if (priv->info->flags & OV772X_FLAG_HFLIP) + val ^= HFLIP_IMG; + ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val); + break; + } + + return ret; +} + static int ov772x_get_chip_id(struct soc_camera_device *icd, struct v4l2_dbg_chip_ident *id) { @@ -768,8 +835,17 @@ static int ov772x_set_fmt(struct soc_camera_device *icd, * set COM3 */ val = priv->fmt->com3; + if (priv->info->flags & OV772X_FLAG_VFLIP) + val |= VFLIP_IMG; + if (priv->info->flags & OV772X_FLAG_HFLIP) + val |= HFLIP_IMG; + if (priv->flag_vflip) + val ^= VFLIP_IMG; + if (priv->flag_hflip) + val ^= HFLIP_IMG; + ret = ov772x_mask_set(priv->client, - COM3, SWAP_MASK, val); + COM3, SWAP_MASK | IMG_MASK, val); if (ret < 0) goto ov772x_set_fmt_error; @@ -887,6 +963,10 @@ static struct soc_camera_ops ov772x_ops = { .try_fmt = ov772x_try_fmt, .set_bus_param = ov772x_set_bus_param, .query_bus_param = ov772x_query_bus_param, + .controls = ov772x_controls, + .num_controls = ARRAY_SIZE(ov772x_controls), + .get_control = ov772x_get_control, + .set_control = ov772x_set_control, .get_chip_id = ov772x_get_chip_id, #ifdef CONFIG_VIDEO_ADV_DEBUG .get_register = ov772x_get_register, -- cgit v1.2.3 From 5f142c1dc4286e15ad35fc32896d12a4badf84b7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: tw9910: bit mask operation fix on tw9910_mask_set. From: Kuninori Morimoto Signed-off-by: Kuninori Morimoto Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/tw9910.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) --- linux/drivers/media/video/tw9910.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/tw9910.c b/linux/drivers/media/video/tw9910.c index 4593cdea7..ed8dca3bf 100644 --- a/linux/drivers/media/video/tw9910.c +++ b/linux/drivers/media/video/tw9910.c @@ -460,9 +460,11 @@ static int tw9910_mask_set(struct i2c_client *client, u8 command, u8 mask, u8 set) { s32 val = i2c_smbus_read_byte_data(client, command); + if (val < 0) + return val; val &= ~mask; - val |= set; + val |= set & mask; return i2c_smbus_write_byte_data(client, command, val); } -- cgit v1.2.3 From 64c5c0e18bea0815ea7a971107b21a6c606bad77 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: sh_mobile_ceu: SOCAM flags are not platform dependent From: Kuninori Morimoto sh_mobile_ceu_camera.c support for signal polarity flags isn't platform dependent, provide them locally. Only the bus width is implementation specific. Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/sh_mobile_ceu_camera.c | 28 ++++++++++++++++++++++++++-- include/media/sh_mobile_ceu.h | 5 +++-- 2 files changed, 29 insertions(+), 4 deletions(-) --- linux/drivers/media/video/sh_mobile_ceu_camera.c | 28 ++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index ee113de47..19b04bfa4 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -102,6 +102,30 @@ struct sh_mobile_ceu_dev { const struct soc_camera_data_format *camera_fmt; }; +static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) +{ + unsigned long flags; + + flags = SOCAM_MASTER | + SOCAM_PCLK_SAMPLE_RISING | + SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_HSYNC_ACTIVE_LOW | + SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_VSYNC_ACTIVE_LOW | + SOCAM_DATA_ACTIVE_HIGH; + + if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS) + flags |= SOCAM_DATAWIDTH_8; + + if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS) + flags |= SOCAM_DATAWIDTH_16; + + if (flags & SOCAM_DATAWIDTH_MASK) + return flags; + + return 0; +} + static void ceu_write(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs, u32 data) { @@ -397,7 +421,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, camera_flags = icd->ops->query_bus_param(icd); common_flags = soc_camera_bus_param_compatible(camera_flags, - pcdev->pdata->flags); + make_bus_param(pcdev)); if (!common_flags) return -EINVAL; @@ -518,7 +542,7 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd) camera_flags = icd->ops->query_bus_param(icd); common_flags = soc_camera_bus_param_compatible(camera_flags, - pcdev->pdata->flags); + make_bus_param(pcdev)); if (!common_flags) return -EINVAL; -- cgit v1.2.3 From 426a59d72f4443f7d8cb949a514b566bc0f64cad Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:12:58 +0100 Subject: sh_mobile_ceu_camera: include NV* formats into the format list only once. From: Guennadi Liakhovetski Currently, if an soc-camera device, connected to the sh_mobile_ceu_camera camera host driver, supports several formats from the UYVY, VYUY, YUYV, YVYU set, the driver would add four NV* formats for each of them. This patch fixes this misbehaviour. Reported-by: Kuninori Morimoto Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/sh_mobile_ceu_camera.c | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) --- linux/drivers/media/video/sh_mobile_ceu_camera.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index 19b04bfa4..29ff02802 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -587,11 +587,29 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, if (ret < 0) return 0; + /* Beginning of a pass */ + if (!idx) + icd->host_priv = NULL; + switch (icd->formats[idx].fourcc) { case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: + if (icd->host_priv) + goto add_single_format; + + /* + * Our case is simple so far: for any of the above four camera + * formats we add all our four synthesized NV* formats, so, + * just marking the device with a single flag suffices. If + * the format generation rules are more complex, you would have + * to actually hang your already added / counted formats onto + * the host_priv pointer and check whether the format you're + * going to add now is already there. + */ + icd->host_priv = (void *)sh_mobile_ceu_formats; + n = ARRAY_SIZE(sh_mobile_ceu_formats); formats += n; for (k = 0; xlate && k < n; k++) { @@ -604,6 +622,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, icd->formats[idx].name); } default: +add_single_format: /* Generic pass-through */ formats++; if (xlate) { -- cgit v1.2.3 From 353a84c516af7a6b6f293a8dc526e76b366db4ff Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:13:23 +0100 Subject: mt9t031: fix gain and hflip controls, register update, and scaling From: Guennadi Liakhovetski Multiple fixes: 1. allow register update by setting the Output Control register to 2 and not 3 2. fix scaling factor calculations 3. recover lost HFLIP control 4. fix Global Gain calculation Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/mt9t031.c | 127 +++++++++++++++++++++++++++-------------- 1 files changed, 84 insertions(+), 43 deletions(-) --- linux/drivers/media/video/mt9t031.c | 127 ++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 43 deletions(-) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/mt9t031.c b/linux/drivers/media/video/mt9t031.c index dd5bd9dd0..aa0e8ec34 100644 --- a/linux/drivers/media/video/mt9t031.c +++ b/linux/drivers/media/video/mt9t031.c @@ -150,7 +150,7 @@ static int mt9t031_init(struct soc_camera_device *icd) if (ret >= 0) ret = reg_write(icd, MT9T031_RESET, 0); if (ret >= 0) - ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3); + ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2); return ret >= 0 ? 0 : -EIO; } @@ -158,14 +158,14 @@ static int mt9t031_init(struct soc_camera_device *icd) static int mt9t031_release(struct soc_camera_device *icd) { /* Disable the chip */ - reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3); + reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2); return 0; } static int mt9t031_start_capture(struct soc_camera_device *icd) { /* Switch to master "normal" mode */ - if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 3) < 0) + if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } @@ -173,7 +173,7 @@ static int mt9t031_start_capture(struct soc_camera_device *icd) static int mt9t031_stop_capture(struct soc_camera_device *icd) { /* Stop sensor readout */ - if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3) < 0) + if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } @@ -201,6 +201,18 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); } +/* Round up minima and round down maxima */ +static void recalculate_limits(struct soc_camera_device *icd, + u16 xskip, u16 yskip) +{ + icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip; + icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip; + icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip; + icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip; + icd->width_max = MT9T031_MAX_WIDTH / xskip; + icd->height_max = MT9T031_MAX_HEIGHT / yskip; +} + static int mt9t031_set_fmt(struct soc_camera_device *icd, __u32 pixfmt, struct v4l2_rect *rect) { @@ -208,54 +220,70 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd, int ret; const u16 hblank = MT9T031_HORIZONTAL_BLANK, vblank = MT9T031_VERTICAL_BLANK; - u16 xbin, xskip = mt9t031->xskip, ybin, yskip = mt9t031->yskip, - width = rect->width * xskip, height = rect->height * yskip; + u16 xbin, xskip, ybin, yskip, width, height, left, top; if (pixfmt) { - /* S_FMT - use binning and skipping for scaling, recalculate */ + /* + * try_fmt has put rectangle within limits. + * S_FMT - use binning and skipping for scaling, recalculate + * limits, used for cropping + */ /* Is this more optimal than just a division? */ for (xskip = 8; xskip > 1; xskip--) - if (rect->width * xskip <= icd->width_max) + if (rect->width * xskip <= MT9T031_MAX_WIDTH) break; for (yskip = 8; yskip > 1; yskip--) - if (rect->height * yskip <= icd->height_max) + if (rect->height * yskip <= MT9T031_MAX_HEIGHT) break; - width = rect->width * xskip; - height = rect->height * yskip; - - dev_dbg(&icd->dev, "xskip %u, width %u, yskip %u, height %u\n", - xskip, width, yskip, height); + recalculate_limits(icd, xskip, yskip); + } else { + /* CROP - no change in scaling, or in limits */ + xskip = mt9t031->xskip; + yskip = mt9t031->yskip; } + /* Make sure we don't exceed sensor limits */ + if (rect->left + rect->width > icd->width_max) + rect->left = (icd->width_max - rect->width) / 2 + icd->x_min; + + if (rect->top + rect->height > icd->height_max) + rect->top = (icd->height_max - rect->height) / 2 + icd->y_min; + + width = rect->width * xskip; + height = rect->height * yskip; + left = rect->left * xskip; + top = rect->top * yskip; + xbin = min(xskip, (u16)3); ybin = min(yskip, (u16)3); - /* Make sure we don't exceed frame limits */ - if (rect->left + width > icd->width_max) - rect->left = (icd->width_max - width) / 2; + dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n", + xskip, width, rect->width, yskip, height, rect->height); - if (rect->top + height > icd->height_max) - rect->top = (icd->height_max - height) / 2; - - /* Could just do roundup(rect->left, [xy]bin); but this is cheaper */ + /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */ switch (xbin) { case 2: - rect->left = (rect->left + 1) & ~1; + left = (left + 3) & ~3; break; case 3: - rect->left = roundup(rect->left, 3); + left = roundup(left, 6); } switch (ybin) { case 2: - rect->top = (rect->top + 1) & ~1; + top = (top + 3) & ~3; break; case 3: - rect->top = roundup(rect->top, 3); + top = roundup(top, 6); } + /* Disable register update, reconfigure atomically */ + ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1); + if (ret < 0) + return ret; + /* Blanking and start values - default... */ ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank); if (ret >= 0) @@ -270,14 +298,14 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd, ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE, ((ybin - 1) << 4) | (yskip - 1)); } - dev_dbg(&icd->dev, "new left %u, top %u\n", rect->left, rect->top); + dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top); /* The caller provides a supported format, as guaranteed by * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ if (ret >= 0) - ret = reg_write(icd, MT9T031_COLUMN_START, rect->left); + ret = reg_write(icd, MT9T031_COLUMN_START, left); if (ret >= 0) - ret = reg_write(icd, MT9T031_ROW_START, rect->top); + ret = reg_write(icd, MT9T031_ROW_START, top); if (ret >= 0) ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1); if (ret >= 0) @@ -302,6 +330,9 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd, mt9t031->yskip = yskip; } + /* Re-enable register update, commit all changes */ + reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1); + return ret < 0 ? ret : 0; } @@ -310,14 +341,14 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd, { struct v4l2_pix_format *pix = &f->fmt.pix; - if (pix->height < icd->height_min) - pix->height = icd->height_min; - if (pix->height > icd->height_max) - pix->height = icd->height_max; - if (pix->width < icd->width_min) - pix->width = icd->width_min; - if (pix->width > icd->width_max) - pix->width = icd->width_max; + if (pix->height < MT9T031_MIN_HEIGHT) + pix->height = MT9T031_MIN_HEIGHT; + if (pix->height > MT9T031_MAX_HEIGHT) + pix->height = MT9T031_MAX_HEIGHT; + if (pix->width < MT9T031_MIN_WIDTH) + pix->width = MT9T031_MIN_WIDTH; + if (pix->width > MT9T031_MAX_WIDTH) + pix->width = MT9T031_MAX_WIDTH; pix->width &= ~0x01; /* has to be even */ pix->height &= ~0x01; /* has to be even */ @@ -389,6 +420,14 @@ static const struct v4l2_queryctrl mt9t031_controls[] = { .maximum = 1, .step = 1, .default_value = 0, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, }, { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, @@ -513,21 +552,23 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro if (data < 0) return -EIO; } else { - /* Pack it into 1.125..15 variable step, register values 9..67 */ + /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ unsigned long range = qctrl->maximum - qctrl->default_value - 1; + /* calculated gain: map 65..127 to 9..1024 step 0.125 */ unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * - 111 + range / 2) / range + 9; + 1015 + range / 2) / range + 9; - if (gain <= 32) + if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ data = gain; - else if (gain <= 64) + else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */ data = ((gain - 32) * 16 + 16) / 32 + 80; else - data = ((gain - 64) * 7 + 28) / 56 + 96; + /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ + data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; - dev_dbg(&icd->dev, "Setting gain from %d to %d\n", - reg_read(icd, MT9T031_GLOBAL_GAIN), data); + dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n", + reg_read(icd, MT9T031_GLOBAL_GAIN), data); data = reg_write(icd, MT9T031_GLOBAL_GAIN, data); if (data < 0) return -EIO; -- cgit v1.2.3 From 9f8456392268399f45cc6a1bc14889c7109975d1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:13:24 +0100 Subject: soc-camera: camera host driver for i.MX3x SoCs From: Guennadi Liakhovetski Tested with 8 bit Bayer and 8 bit monochrome video. Signed-off-by: Guennadi Liakhovetski --- arch/arm/plat-mxc/include/mach/mx3_camera.h | 52 ++ drivers/media/video/Kconfig | 7 + drivers/media/video/Makefile | 5 +- drivers/media/video/mx3_camera.c | 1183 +++++++++++++++++++++++++++ 4 files changed, 1245 insertions(+), 2 deletions(-) create mode 100644 arch/arm/plat-mxc/include/mach/mx3_camera.h create mode 100644 drivers/media/video/mx3_camera.c --- linux/drivers/media/video/Kconfig | 7 + linux/drivers/media/video/Makefile | 5 +- linux/drivers/media/video/mx3_camera.c | 1183 ++++++++++++++++++++++++++++++++ 3 files changed, 1193 insertions(+), 2 deletions(-) create mode 100644 linux/drivers/media/video/mx3_camera.c (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 19cf3b8f6..3e4ce4aad 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -779,6 +779,13 @@ config SOC_CAMERA_OV772X help This is a ov772x camera driver +config VIDEO_MX3 + tristate "i.MX3x Camera Sensor Interface driver" + depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA + select VIDEOBUF_DMA_CONTIG + ---help--- + This is a v4l2 driver for the i.MX3x Camera Sensor Interface + config VIDEO_PXA27x tristate "PXA27x Quick Capture Interface driver" depends on VIDEO_DEV && PXA27x && SOC_CAMERA diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index 72f6d03d2..6e2c69569 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -134,10 +134,11 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ -obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o +obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o +obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o -obj-$(CONFIG_SOC_CAMERA) += soc_camera.o +obj-$(CONFIG_SOC_CAMERA) += soc_camera.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o diff --git a/linux/drivers/media/video/mx3_camera.c b/linux/drivers/media/video/mx3_camera.c new file mode 100644 index 000000000..a925d093b --- /dev/null +++ b/linux/drivers/media/video/mx3_camera.c @@ -0,0 +1,1183 @@ +/* + * V4L2 Driver for i.MX3x camera host + * + * Copyright (C) 2008 + * Guennadi Liakhovetski, DENX Software Engineering, + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define MX3_CAM_DRV_NAME "mx3-camera" + +/* CMOS Sensor Interface Registers */ +#define CSI_REG_START 0x60 + +#define CSI_SENS_CONF (0x60 - CSI_REG_START) +#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START) +#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START) +#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START) +#define CSI_TST_CTRL (0x70 - CSI_REG_START) +#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START) +#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START) +#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START) +#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START) +#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START) + +#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 +#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 +#define CSI_SENS_CONF_DATA_POL_SHIFT 2 +#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 +#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 +#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7 +#define CSI_SENS_CONF_DATA_FMT_SHIFT 8 +#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10 +#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 +#define CSI_SENS_CONF_DIVRATIO_SHIFT 16 + +#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT) +#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT) +#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT) + +#define MAX_VIDEO_MEM 16 + +struct mx3_camera_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + const struct soc_camera_data_format *fmt; + + /* One descriptot per scatterlist (per frame) */ + struct dma_async_tx_descriptor *txd; + + /* We have to "build" a scatterlist ourselves - one element per frame */ + struct scatterlist sg; +}; + +/** + * struct mx3_camera_dev - i.MX3x camera (CSI) object + * @dev: camera device, to which the coherent buffer is attached + * @icd: currently attached camera sensor + * @clk: pointer to clock + * @base: remapped register base address + * @pdata: platform data + * @platform_flags: platform flags + * @mclk: master clock frequency in Hz + * @capture: list of capture videobuffers + * @lock: protects video buffer lists + * @active: active video buffer + * @idmac_channel: array of pointers to IPU DMAC DMA channels + * @soc_host: embedded soc_host object + */ +struct mx3_camera_dev { + struct device *dev; + /* + * i.MX3x is only supposed to handle one camera on its Camera Sensor + * Interface. If anyone ever builds hardware to enable more than one + * camera _simultaneously_, they will have to modify this driver too + */ + struct soc_camera_device *icd; + struct clk *clk; + + void __iomem *base; + + struct mx3_camera_pdata *pdata; + + unsigned long platform_flags; + unsigned long mclk; + + struct list_head capture; + spinlock_t lock; /* Protects video buffer lists */ + struct mx3_camera_buffer *active; + + /* IDMAC / dmaengine interface */ + struct idmac_channel *idmac_channel[1]; /* We need one channel */ + + struct soc_camera_host soc_host; +}; + +struct dma_chan_request { + struct mx3_camera_dev *mx3_cam; + enum ipu_channel id; +}; + +static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt); + +static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) +{ + return __raw_readl(mx3->base + reg); +} + +static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg) +{ + __raw_writel(value, mx3->base + reg); +} + +/* Called from the IPU IDMAC ISR */ +static void mx3_cam_dma_done(void *arg) +{ + struct idmac_tx_desc *desc = to_tx_desc(arg); + struct dma_chan *chan = desc->txd.chan; + struct idmac_channel *ichannel = to_idmac_chan(chan); + struct mx3_camera_dev *mx3_cam = ichannel->client; + struct videobuf_buffer *vb; + + dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", + desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0); + + spin_lock(&mx3_cam->lock); + if (mx3_cam->active) { + vb = &mx3_cam->active->vb; + + list_del_init(&vb->queue); + vb->state = VIDEOBUF_DONE; + do_gettimeofday(&vb->ts); + vb->field_count++; + wake_up(&vb->done); + } + + if (list_empty(&mx3_cam->capture)) { + mx3_cam->active = NULL; + spin_unlock(&mx3_cam->lock); + + /* + * stop capture - without further buffers IPU_CHA_BUF0_RDY will + * not get updated + */ + return; + } + + mx3_cam->active = list_entry(mx3_cam->capture.next, + struct mx3_camera_buffer, vb.queue); + mx3_cam->active->vb.state = VIDEOBUF_ACTIVE; + spin_unlock(&mx3_cam->lock); +} + +static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf) +{ + struct soc_camera_device *icd = vq->priv_data; + struct videobuf_buffer *vb = &buf->vb; + struct dma_async_tx_descriptor *txd = buf->txd; + struct idmac_channel *ichan; + + BUG_ON(in_interrupt()); + + dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + vb, vb->baddr, vb->bsize); + + /* + * This waits until this buffer is out of danger, i.e., until it is no + * longer in STATE_QUEUED or STATE_ACTIVE + */ + videobuf_waiton(vb, 0, 0); + if (txd) { + ichan = to_idmac_chan(txd->chan); + async_tx_ack(txd); + } + videobuf_dma_contig_free(vq, vb); + buf->txd = NULL; + + vb->state = VIDEOBUF_NEEDS_INIT; +} + +/* + * Videobuf operations + */ + +/* + * Calculate the __buffer__ (not data) size and number of buffers. + * Called with .vb_lock held + */ +static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, + unsigned int *size) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + /* + * bits-per-pixel (depth) as specified in camera's pixel format does + * not necessarily match what the camera interface writes to RAM, but + * it should be good enough for now. + */ + unsigned int bpp = DIV_ROUND_UP(icd->current_fmt->depth, 8); + + if (!mx3_cam->idmac_channel[0]) + return -EINVAL; + + *size = icd->width * icd->height * bpp; + + if (!*count) + *count = 32; + + if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) + *count = MAX_VIDEO_MEM * 1024 * 1024 / *size; + + return 0; +} + +/* Called with .vb_lock held */ +static int mx3_videobuf_prepare(struct videobuf_queue *vq, + struct videobuf_buffer *vb, enum v4l2_field field) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct mx3_camera_buffer *buf = + container_of(vb, struct mx3_camera_buffer, vb); + /* current_fmt _must_ always be set */ + size_t new_size = icd->width * icd->height * + ((icd->current_fmt->depth + 7) >> 3); + int ret; + + /* + * I think, in buf_prepare you only have to protect global data, + * the actual buffer is yours + */ + + if (buf->fmt != icd->current_fmt || + vb->width != icd->width || + vb->height != icd->height || + vb->field != field) { + buf->fmt = icd->current_fmt; + vb->width = icd->width; + vb->height = icd->height; + vb->field = field; + if (vb->state != VIDEOBUF_NEEDS_INIT) + free_buffer(vq, buf); + } + + if (vb->baddr && vb->bsize < new_size) { + /* User provided buffer, but it is too small */ + ret = -ENOMEM; + goto out; + } + + if (vb->state == VIDEOBUF_NEEDS_INIT) { + struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; + struct scatterlist *sg = &buf->sg; + + /* + * The total size of video-buffers that will be allocated / mapped. + * *size that we calculated in videobuf_setup gets assigned to + * vb->bsize, and now we use the same calculation to get vb->size. + */ + vb->size = new_size; + + /* This actually (allocates and) maps buffers */ + ret = videobuf_iolock(vq, vb, NULL); + if (ret) + goto fail; + + /* + * We will have to configure the IDMAC channel. It has two slots + * for DMA buffers, we shall enter the first two buffers there, + * and then submit new buffers in DMA-ready interrupts + */ + sg_init_table(sg, 1); + sg_dma_address(sg) = videobuf_to_dma_contig(vb); + sg_dma_len(sg) = vb->size; + + buf->txd = ichan->dma_chan.device->device_prep_slave_sg( + &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT); + if (!buf->txd) { + ret = -EIO; + goto fail; + } + + buf->txd->callback_param = buf->txd; + buf->txd->callback = mx3_cam_dma_done; + + vb->state = VIDEOBUF_PREPARED; + } + + return 0; + +fail: + free_buffer(vq, buf); +out: + return ret; +} + +static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) +{ + /* Add more formats as need arises and test possibilities appear... */ + switch (fourcc) { + case V4L2_PIX_FMT_RGB565: + return IPU_PIX_FMT_RGB565; + case V4L2_PIX_FMT_RGB24: + return IPU_PIX_FMT_RGB24; + case V4L2_PIX_FMT_RGB332: + return IPU_PIX_FMT_RGB332; + case V4L2_PIX_FMT_YUV422P: + return IPU_PIX_FMT_YVU422P; + default: + return IPU_PIX_FMT_GENERIC; + } +} + +/* Called with .vb_lock held */ +static void mx3_videobuf_queue(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct mx3_camera_buffer *buf = + container_of(vb, struct mx3_camera_buffer, vb); + struct dma_async_tx_descriptor *txd = buf->txd; + struct idmac_channel *ichan = to_idmac_chan(txd->chan); + struct idmac_video_param *video = &ichan->params.video; + const struct soc_camera_data_format *data_fmt = icd->current_fmt; + dma_cookie_t cookie; + unsigned long flags; + + /* This is the configuration of one sg-element */ + video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); + video->out_width = icd->width; + video->out_height = icd->height; + video->out_stride = icd->width; + +#ifdef DEBUG + /* helps to see what DMA actually has written */ + memset((void *)vb->baddr, 0xaa, vb->bsize); +#endif + + spin_lock_irqsave(&mx3_cam->lock, flags); + + list_add_tail(&vb->queue, &mx3_cam->capture); + + if (!mx3_cam->active) { + mx3_cam->active = buf; + vb->state = VIDEOBUF_ACTIVE; + } else { + vb->state = VIDEOBUF_QUEUED; + } + + spin_unlock_irqrestore(&mx3_cam->lock, flags); + + cookie = txd->tx_submit(txd); + dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg)); + if (cookie >= 0) + return; + + /* Submit error */ + vb->state = VIDEOBUF_PREPARED; + + spin_lock_irqsave(&mx3_cam->lock, flags); + + list_del_init(&vb->queue); + + if (mx3_cam->active == buf) + mx3_cam->active = NULL; + + spin_unlock_irqrestore(&mx3_cam->lock, flags); +} + +/* Called with .vb_lock held */ +static void mx3_videobuf_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) +{ + struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct mx3_camera_buffer *buf = + container_of(vb, struct mx3_camera_buffer, vb); + unsigned long flags; + + dev_dbg(&icd->dev, "Release%s DMA 0x%08x (state %d), queue %sempty\n", + mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), + vb->state, list_empty(&vb->queue) ? "" : "not "); + spin_lock_irqsave(&mx3_cam->lock, flags); + if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && + !list_empty(&vb->queue)) { + vb->state = VIDEOBUF_ERROR; + + list_del_init(&vb->queue); + if (mx3_cam->active == buf) + mx3_cam->active = NULL; + } + spin_unlock_irqrestore(&mx3_cam->lock, flags); + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops mx3_videobuf_ops = { + .buf_setup = mx3_videobuf_setup, + .buf_prepare = mx3_videobuf_prepare, + .buf_queue = mx3_videobuf_queue, + .buf_release = mx3_videobuf_release, +}; + +static void mx3_camera_init_videobuf(struct videobuf_queue *q, + struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + + videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev, + &mx3_cam->lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, + sizeof(struct mx3_camera_buffer), icd); +} + +/* First part of ipu_csi_init_interface() */ +static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam, + struct soc_camera_device *icd) +{ + u32 conf; + long rate; + + /* Set default size: ipu_csi_set_window_size() */ + csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE); + /* ...and position to 0:0: ipu_csi_set_window_pos() */ + conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; + csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL); + + /* We use only gated clock synchronisation mode so far */ + conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT; + + /* Set generic data, platform-biggest bus-width */ + conf |= CSI_SENS_CONF_DATA_FMT_BAYER; + + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) + conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) + conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) + conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/ + conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + + if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC) + conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC) + conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_DP) + conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_PCP) + conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_HSP) + conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; + if (mx3_cam->platform_flags & MX3_CAMERA_VSP) + conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; + + /* ipu_csi_init_interface() */ + csi_reg_write(mx3_cam, conf, CSI_SENS_CONF); + + clk_enable(mx3_cam->clk); + rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); + dev_dbg(&icd->dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate); + if (rate) + clk_set_rate(mx3_cam->clk, rate); +} + +/* Called with .video_lock held */ +static int mx3_camera_add_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + int ret; + + if (mx3_cam->icd) { + ret = -EBUSY; + goto ebusy; + } + + mx3_camera_activate(mx3_cam, icd); + ret = icd->ops->init(icd); + if (ret < 0) { + clk_disable(mx3_cam->clk); + goto einit; + } + + mx3_cam->icd = icd; + +einit: +ebusy: + if (!ret) + dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n", + icd->devnum); + + return ret; +} + +/* Called with .video_lock held */ +static void mx3_camera_remove_device(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; + + BUG_ON(icd != mx3_cam->icd); + + if (*ichan) { + dma_release_channel(&(*ichan)->dma_chan); + *ichan = NULL; + } + + icd->ops->release(icd); + + clk_disable(mx3_cam->clk); + + mx3_cam->icd = NULL; + + dev_info(&icd->dev, "MX3 Camera driver detached from camera %d\n", + icd->devnum); +} + +static bool channel_change_requested(struct soc_camera_device *icd, + const struct soc_camera_format_xlate *xlate, + __u32 pixfmt, struct v4l2_rect *rect) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; + + /* So far only one configuration is supported */ + return pixfmt || (ichan && rect->width * rect->height > + icd->width * icd->height); +} + +static int test_platform_param(struct mx3_camera_dev *mx3_cam, + unsigned char buswidth, unsigned long *flags) +{ + /* + * Platform specified synchronization and pixel clock polarities are + * only a recommendation and are only used during probing. MX3x + * camera interface only works in master mode, i.e., uses HSYNC and + * VSYNC signals from the sensor + */ + *flags = SOCAM_MASTER | + SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_HSYNC_ACTIVE_LOW | + SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_VSYNC_ACTIVE_LOW | + SOCAM_PCLK_SAMPLE_RISING | + SOCAM_PCLK_SAMPLE_FALLING | + SOCAM_DATA_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_LOW; + + /* If requested data width is supported by the platform, use it or any + * possible lower value - i.MX31 is smart enough to schift bits */ + switch (buswidth) { + case 15: + if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)) + return -EINVAL; + *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | + SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; + break; + case 10: + if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)) + return -EINVAL; + *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | + SOCAM_DATAWIDTH_4; + break; + case 8: + if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)) + return -EINVAL; + *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; + break; + case 4: + if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)) + return -EINVAL; + *flags |= SOCAM_DATAWIDTH_4; + break; + default: + dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth); + return -EINVAL; + } + + return 0; +} + +static int mx3_camera_try_bus_param(struct soc_camera_device *icd, + const unsigned int depth) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + unsigned long bus_flags, camera_flags; + int ret = test_platform_param(mx3_cam, depth, &bus_flags); + + dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret); + + if (ret < 0) + return ret; + + camera_flags = icd->ops->query_bus_param(icd); + + ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); + if (ret < 0) + dev_warn(&icd->dev, "Flags incompatible: camera %lx, host %lx\n", + camera_flags, bus_flags); + + return ret; +} + +static bool chan_filter(struct dma_chan *chan, void *arg) +{ + struct dma_chan_request *rq = arg; + struct mx3_camera_pdata *pdata; + + if (!rq) + return false; + + pdata = rq->mx3_cam->dev->platform_data; + + return rq->id == chan->chan_id && + pdata->dma_dev == chan->device->dev; +} + +static const struct soc_camera_data_format mx3_camera_formats[] = { + { + .name = "Bayer (sRGB) 8 bit", + .depth = 8, + .fourcc = V4L2_PIX_FMT_SBGGR8, + .colorspace = V4L2_COLORSPACE_SRGB, + }, { + .name = "Monochrome 8 bit", + .depth = 8, + .fourcc = V4L2_PIX_FMT_GREY, + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; + +static bool buswidth_supported(struct soc_camera_host *ici, int depth) +{ + struct mx3_camera_dev *mx3_cam = ici->priv; + + switch (depth) { + case 4: + return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4); + case 8: + return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8); + case 10: + return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10); + case 15: + return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15); + } + return false; +} + +static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, + struct soc_camera_format_xlate *xlate) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int formats = 0, buswidth, ret; + + buswidth = icd->formats[idx].depth; + + if (!buswidth_supported(ici, buswidth)) + return 0; + + ret = mx3_camera_try_bus_param(icd, buswidth); + if (ret < 0) + return 0; + + switch (icd->formats[idx].fourcc) { + case V4L2_PIX_FMT_SGRBG10: + formats++; + if (xlate) { + xlate->host_fmt = &mx3_camera_formats[0]; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = buswidth; + xlate++; + dev_dbg(&ici->dev, "Providing format %s using %s\n", + mx3_camera_formats[0].name, + icd->formats[idx].name); + } + goto passthrough; + case V4L2_PIX_FMT_Y16: + formats++; + if (xlate) { + xlate->host_fmt = &mx3_camera_formats[1]; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = buswidth; + xlate++; + dev_dbg(&ici->dev, "Providing format %s using %s\n", + mx3_camera_formats[0].name, + icd->formats[idx].name); + } + default: +passthrough: + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = icd->formats + idx; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = buswidth; + xlate++; + dev_dbg(&ici->dev, + "Providing format %s in pass-through mode\n", + icd->formats[idx].name); + } + } + + return formats; +} + +static int mx3_camera_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + const struct soc_camera_format_xlate *xlate; + u32 ctrl, width_field, height_field; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (pixfmt && !xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + /* + * We now know pixel formats and can decide upon DMA-channel(s) + * So far only direct camera-to-memory is supported + */ + if (channel_change_requested(icd, xlate, pixfmt, rect)) { + dma_cap_mask_t mask; + struct dma_chan *chan; + struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; + /* We have to use IDMAC_IC_7 for Bayer / generic data */ + struct dma_chan_request rq = {.mx3_cam = mx3_cam, + .id = IDMAC_IC_7}; + + if (*ichan) { + struct videobuf_buffer *vb, *_vb; + dma_release_channel(&(*ichan)->dma_chan); + *ichan = NULL; + mx3_cam->active = NULL; + list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) { + list_del_init(&vb->queue); + vb->state = VIDEOBUF_ERROR; + wake_up(&vb->done); + } + } + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_PRIVATE, mask); + chan = dma_request_channel(mask, chan_filter, &rq); + if (!chan) + return -EBUSY; + + *ichan = to_idmac_chan(chan); + (*ichan)->client = mx3_cam; + } + + /* + * Might have to perform a complete interface initialisation like in + * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider + * mxc_v4l2_s_fmt() + */ + + /* Setup frame size - this cannot be changed on-the-fly... */ + width_field = rect->width - 1; + height_field = rect->height - 1; + csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); + + csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); + csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2); + + csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE); + + /* ...and position */ + ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; + /* Sensor does the cropping */ + csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); + + /* + * No need to free resources here if we fail, we'll see if we need to + * do this next time we are called + */ + + ret = icd->ops->set_fmt(icd, pixfmt ? xlate->cam_fmt->fourcc : 0, rect); + if (pixfmt && !ret) { + icd->buswidth = xlate->buswidth; + icd->current_fmt = xlate->host_fmt; + } + + return ret; +} + +static int mx3_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + __u32 pixfmt = pix->pixelformat; + enum v4l2_field field; + int ret; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (pixfmt && !xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + /* limit to MX3 hardware capabilities */ + if (pix->height > 4096) + pix->height = 4096; + if (pix->width > 4096) + pix->width = 4096; + + pix->bytesperline = pix->width * + DIV_ROUND_UP(xlate->host_fmt->depth, 8); + pix->sizeimage = pix->height * pix->bytesperline; + + /* camera has to see its format, but the user the original one */ + pix->pixelformat = xlate->cam_fmt->fourcc; + /* limit to sensor capabilities */ + ret = icd->ops->try_fmt(icd, f); + pix->pixelformat = xlate->host_fmt->fourcc; + + field = pix->field; + + if (field == V4L2_FIELD_ANY) { + pix->field = V4L2_FIELD_NONE; + } else if (field != V4L2_FIELD_NONE) { + dev_err(&icd->dev, "Field type %d unsupported.\n", field); + return -EINVAL; + } + + return ret; +} + +static int mx3_camera_reqbufs(struct soc_camera_file *icf, + struct v4l2_requestbuffers *p) +{ + return 0; +} + +static unsigned int mx3_camera_poll(struct file *file, poll_table *pt) +{ + struct soc_camera_file *icf = file->private_data; + + return videobuf_poll_stream(file, &icf->vb_vidq, pt); +} + +static int mx3_camera_querycap(struct soc_camera_host *ici, + struct v4l2_capability *cap) +{ + /* cap->name is set by the firendly caller:-> */ + strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); + cap->version = KERNEL_VERSION(0, 2, 2); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + + return 0; +} + +static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct mx3_camera_dev *mx3_cam = ici->priv; + unsigned long bus_flags, camera_flags, common_flags; + u32 dw, sens_conf; + int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags); + const struct soc_camera_format_xlate *xlate; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", + icd->buswidth, ret); + + if (ret < 0) + return ret; + + camera_flags = icd->ops->query_bus_param(icd); + + common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); + if (!common_flags) { + dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n", + camera_flags, bus_flags); + return -EINVAL; + } + + /* Make choices, based on platform preferences */ + if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if (mx3_cam->platform_flags & MX3_CAMERA_HSP) + common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if (mx3_cam->platform_flags & MX3_CAMERA_VSP) + common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && + (common_flags & SOCAM_DATA_ACTIVE_LOW)) { + if (mx3_cam->platform_flags & MX3_CAMERA_DP) + common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_DATA_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && + (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { + if (mx3_cam->platform_flags & MX3_CAMERA_PCP) + common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; + else + common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; + } + + /* Make the camera work in widest common mode, we'll take care of + * the rest */ + if (common_flags & SOCAM_DATAWIDTH_15) + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_15; + else if (common_flags & SOCAM_DATAWIDTH_10) + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_10; + else if (common_flags & SOCAM_DATAWIDTH_8) + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_8; + else + common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | + SOCAM_DATAWIDTH_4; + + ret = icd->ops->set_bus_param(icd, common_flags); + if (ret < 0) + return ret; + + /* + * So far only gated clock mode is supported. Add a line + * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) | + * below and select the required mode when supporting other + * synchronisation protocols. + */ + sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) & + ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) | + (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) | + (1 << CSI_SENS_CONF_DATA_POL_SHIFT) | + (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) | + (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) | + (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT)); + + /* TODO: Support RGB and YUV formats */ + + /* This has been set in mx3_camera_activate(), but we clear it above */ + sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; + + if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) + sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; + if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) + sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; + if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) + sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; + if (common_flags & SOCAM_DATA_ACTIVE_LOW) + sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; + + /* Just do what we're asked to do */ + switch (xlate->host_fmt->depth) { + case 4: + dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + break; + case 8: + dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + break; + case 10: + dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + break; + default: + /* + * Actually it can only be 15 now, default is just to silence + * compiler warnings + */ + case 15: + dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; + } + + csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); + + dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw); + + return 0; +} + +static struct soc_camera_host_ops mx3_soc_camera_host_ops = { + .owner = THIS_MODULE, + .add = mx3_camera_add_device, + .remove = mx3_camera_remove_device, +#ifdef CONFIG_PM + .suspend = mx3_camera_suspend, + .resume = mx3_camera_resume, +#endif + .set_fmt = mx3_camera_set_fmt, + .try_fmt = mx3_camera_try_fmt, + .get_formats = mx3_camera_get_formats, + .init_videobuf = mx3_camera_init_videobuf, + .reqbufs = mx3_camera_reqbufs, + .poll = mx3_camera_poll, + .querycap = mx3_camera_querycap, + .set_bus_param = mx3_camera_set_bus_param, +}; + +static int mx3_camera_probe(struct platform_device *pdev) +{ + struct mx3_camera_dev *mx3_cam; + struct resource *res; + void __iomem *base; + int err = 0; + struct soc_camera_host *soc_host; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENODEV; + goto egetres; + } + + mx3_cam = vmalloc(sizeof(*mx3_cam)); + if (!mx3_cam) { + dev_err(&pdev->dev, "Could not allocate mx3 camera object\n"); + err = -ENOMEM; + goto ealloc; + } + memset(mx3_cam, 0, sizeof(*mx3_cam)); + + mx3_cam->clk = clk_get(&pdev->dev, "csi_clk"); + if (IS_ERR(mx3_cam->clk)) { + err = PTR_ERR(mx3_cam->clk); + goto eclkget; + } + + dev_set_drvdata(&pdev->dev, mx3_cam); + + mx3_cam->pdata = pdev->dev.platform_data; + mx3_cam->platform_flags = mx3_cam->pdata->flags; + if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | + MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 | + MX3_CAMERA_DATAWIDTH_15))) { + /* Platform hasn't set available data widths. This is bad. + * Warn and use a default. */ + dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " + "data widths, using default 8 bit\n"); + mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; + } + + mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; + if (!mx3_cam->mclk) { + dev_warn(&pdev->dev, + "mclk_10khz == 0! Please, fix your platform data. " + "Using default 20MHz\n"); + mx3_cam->mclk = 20000000; + } + + /* list of video-buffers */ + INIT_LIST_HEAD(&mx3_cam->capture); + spin_lock_init(&mx3_cam->lock); + + base = ioremap(res->start, res->end - res->start + 1); + if (!base) { + err = -ENOMEM; + goto eioremap; + } + + mx3_cam->base = base; + mx3_cam->dev = &pdev->dev; + + soc_host = &mx3_cam->soc_host; + soc_host->drv_name = MX3_CAM_DRV_NAME; + soc_host->ops = &mx3_soc_camera_host_ops; + soc_host->priv = mx3_cam; + soc_host->dev.parent = &pdev->dev; + soc_host->nr = pdev->id; + err = soc_camera_host_register(soc_host); + if (err) + goto ecamhostreg; + + /* IDMAC interface */ + dmaengine_get(); + + return 0; + +ecamhostreg: + iounmap(base); +eioremap: + clk_put(mx3_cam->clk); +eclkget: + vfree(mx3_cam); +ealloc: +egetres: + return err; +} + +static int __devexit mx3_camera_remove(struct platform_device *pdev) +{ + struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev); + + clk_put(mx3_cam->clk); + + soc_camera_host_unregister(&mx3_cam->soc_host); + + iounmap(mx3_cam->base); + + /* + * The channel has either not been allocated, + * or should have been released + */ + if (WARN_ON(mx3_cam->idmac_channel[0])) + dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan); + + vfree(mx3_cam); + + dmaengine_put(); + + dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n"); + + return 0; +} + +static struct platform_driver mx3_camera_driver = { + .driver = { + .name = MX3_CAM_DRV_NAME, + }, + .probe = mx3_camera_probe, + .remove = __exit_p(mx3_camera_remove), +}; + + +static int __devinit mx3_camera_init(void) +{ + return platform_driver_register(&mx3_camera_driver); +} + +static void __exit mx3_camera_exit(void) +{ + platform_driver_unregister(&mx3_camera_driver); +} + +module_init(mx3_camera_init); +module_exit(mx3_camera_exit); + +MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a43bb4e65ce2015ec503f7933fbd136271d80c34 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 16:13:24 +0100 Subject: mt9m111: Call icl->reset() on mt9m111_reset(). From: Antonio Ospite Call icl->reset() on mt9m111_reset(). Signed-off-by: Antonio Ospite Acked-by: Robert Jarzmik Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/mt9m111.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) --- linux/drivers/media/video/mt9m111.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'linux/drivers/media/video') diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c index b2989c0f2..3ae675a42 100644 --- a/linux/drivers/media/video/mt9m111.c +++ b/linux/drivers/media/video/mt9m111.c @@ -393,6 +393,8 @@ static int mt9m111_disable(struct soc_camera_device *icd) static int mt9m111_reset(struct soc_camera_device *icd) { + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct soc_camera_link *icl = mt9m111->client->dev.platform_data; int ret; ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); @@ -401,6 +403,10 @@ static int mt9m111_reset(struct soc_camera_device *icd) if (!ret) ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE | MT9M111_RESET_RESET_SOC); + + if (icl->reset) + icl->reset(&mt9m111->client->dev); + return ret; } -- cgit v1.2.3