diff options
author | Linus Torvalds | 2023-02-26 11:47:26 -0800 |
---|---|---|
committer | Linus Torvalds | 2023-02-26 11:47:26 -0800 |
commit | 4b8c673b761e74add4fd185d806ac16c9b40158f (patch) | |
tree | b7589b0844fc3306e8886228d4290eaff26456c6 | |
parent | d4563201f33a022fc0353033d9dfeb1606a88330 (diff) | |
parent | 3e62aba8284de0994a669d07983299242e68fe72 (diff) |
Merge tag 'media/v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- Removal of several VB1-only deprecated drivers: cpia2, fsl-viu, meye,
stkwebcam, tm6000, vpfe_capture and zr364xx
- saa7146 recovered from staging/deprecated. We opted to give ti a
chance, and, instead of deprecating it, the intention is to write
patches migrating it from VB1 to VB2.
- av7110 returned from staging/deprecated/ to staging/ as we're not
planning on dropping it any time soon
- media controller API has gained experimental support for G_ROUTING
and streams API. No drivers use it right now. We're planning to add
one after -rc1, giving some time to experience the API and eventually
have changes during the next development cycle
- New sensor drivers: imx296, imx415, ov8858
- Atomisp had lots of changes, specially on its sensor's interface,
making atomisp sensor drivers closer to normal sensor drivers
- media controller kAPI has gained some helpers to traverse pipelines
- uvcvideo now better support power line control
- lots of bug fixes, cleanups and driver improvements
* tag 'media/v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (296 commits)
media: imx-mipi-csis: Check csis_fmt validity before use
media: v4l2-subdev.c: clear stream field
media: v4l2-ctrls-api.c: move ctrl->is_new = 1 to the correct line
media: Revert "media: saa7146: deprecate hexium_gemini/orion, mxb and ttpci"
media: Revert "media: av7110: move to staging/media/deprecated/saa7146"
media: imx-pxp: convert to regmap
media: imx-pxp: Use non-threaded IRQ
media: imx-pxp: Introduce pxp_read() and pxp_write() wrappers
media: imx-pxp: Implement frame size enumeration
media: imx-pxp: Pass pixel format value to find_format()
media: imx-pxp: Add media controller support
media: imx-pxp: Don't set bus_info manually in .querycap()
media: imx-pxp: Sort headers alphabetically
media: imx-pxp: add support for i.MX7D
media: imx-pxp: make data_path_ctrl0 platform dependent
media: imx-pxp: disable LUT block
media: imx-pxp: explicitly disable unused blocks
media: imx-pxp: extract helper function to setup data path
media: imx-pxp: detect PXP version
media: dt-bindings: media: fsl-pxp: convert to yaml
...
341 files changed, 10957 insertions, 26765 deletions
diff --git a/.clang-format b/.clang-format index b62836419ea3..2c61b4553374 100644 --- a/.clang-format +++ b/.clang-format @@ -190,6 +190,7 @@ ForEachMacros: - 'for_each_active_dev_scope' - 'for_each_active_drhd_unit' - 'for_each_active_iommu' + - 'for_each_active_route' - 'for_each_aggr_pgid' - 'for_each_available_child_of_node' - 'for_each_bench' diff --git a/Documentation/admin-guide/media/cec.rst b/Documentation/admin-guide/media/cec.rst index 5c7259371494..14ec3ff317c2 100644 --- a/Documentation/admin-guide/media/cec.rst +++ b/Documentation/admin-guide/media/cec.rst @@ -340,14 +340,14 @@ and IO24. Monitoring the HPD an 5V lines is not necessary, but it is helpful. This kernel patch will hook up the cec-gpio driver correctly to e.g. ``arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts``:: - cec-gpio@7 { + cec@7 { compatible = "cec-gpio"; cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; }; - cec-gpio@8 { + cec@8 { compatible = "cec-gpio"; cec-gpios = <&gpio 8 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; hpd-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; diff --git a/Documentation/admin-guide/media/cpia2.rst b/Documentation/admin-guide/media/cpia2.rst deleted file mode 100644 index f6ffef686462..000000000000 --- a/Documentation/admin-guide/media/cpia2.rst +++ /dev/null @@ -1,145 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -The cpia2 driver -================ - -Authors: Peter Pregler <Peter_Pregler@email.com>, -Scott J. Bertin <scottbertin@yahoo.com>, and -Jarl Totland <Jarl.Totland@bdc.no> for the original cpia driver, which -this one was modelled from. - -Introduction ------------- - -This is a driver for STMicroelectronics's CPiA2 (second generation -Colour Processor Interface ASIC) based cameras. This camera outputs an MJPEG -stream at up to vga size. It implements the Video4Linux interface as much as -possible. Since the V4L interface does not support compressed formats, only -an mjpeg enabled application can be used with the camera. We have modified the -gqcam application to view this stream. - -The driver is implemented as two kernel modules. The cpia2 module -contains the camera functions and the V4L interface. The cpia2_usb module -contains usb specific functions. The main reason for this was the size of the -module was getting out of hand, so I separated them. It is not likely that -there will be a parallel port version. - -Features --------- - -- Supports cameras with the Vision stv6410 (CIF) and stv6500 (VGA) cmos - sensors. I only have the vga sensor, so can't test the other. -- Image formats: VGA, QVGA, CIF, QCIF, and a number of sizes in between. - VGA and QVGA are the native image sizes for the VGA camera. CIF is done - in the coprocessor by scaling QVGA. All other sizes are done by clipping. -- Palette: YCrCb, compressed with MJPEG. -- Some compression parameters are settable. -- Sensor framerate is adjustable (up to 30 fps CIF, 15 fps VGA). -- Adjust brightness, color, contrast while streaming. -- Flicker control settable for 50 or 60 Hz mains frequency. - -Making and installing the stv672 driver modules ------------------------------------------------ - -Requirements -~~~~~~~~~~~~ - -Video4Linux must be either compiled into the kernel or -available as a module. Video4Linux2 is automatically detected and made -available at compile time. - -Setup -~~~~~ - -Use ``modprobe cpia2`` to load and ``modprobe -r cpia2`` to unload. This -may be done automatically by your distribution. - -Driver options -~~~~~~~~~~~~~~ - -.. tabularcolumns:: |p{13ex}|L| - - -============== ======================================================== -Option Description -============== ======================================================== -video_nr video device to register (0=/dev/video0, etc) - range -1 to 64. default is -1 (first available) - If you have more than 1 camera, this MUST be -1. -buffer_size Size for each frame buffer in bytes (default 68k) -num_buffers Number of frame buffers (1-32, default 3) -alternate USB Alternate (2-7, default 7) -flicker_freq Frequency for flicker reduction(50 or 60, default 60) -flicker_mode 0 to disable, or 1 to enable flicker reduction. - (default 0). This is only effective if the camera - uses a stv0672 coprocessor. -============== ======================================================== - -Setting the options -~~~~~~~~~~~~~~~~~~~ - -If you are using modules, edit /etc/modules.conf and add an options -line like this:: - - options cpia2 num_buffers=3 buffer_size=65535 - -If the driver is compiled into the kernel, at boot time specify them -like this:: - - cpia2.num_buffers=3 cpia2.buffer_size=65535 - -What buffer size should I use? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The maximum image size depends on the alternate you choose, and the -frame rate achieved by the camera. If the compression engine is able to -keep up with the frame rate, the maximum image size is given by the table -below. - -The compression engine starts out at maximum compression, and will -increase image quality until it is close to the size in the table. As long -as the compression engine can keep up with the frame rate, after a short time -the images will all be about the size in the table, regardless of resolution. - -At low alternate settings, the compression engine may not be able to -compress the image enough and will reduce the frame rate by producing larger -images. - -The default of 68k should be good for most users. This will handle -any alternate at frame rates down to 15fps. For lower frame rates, it may -be necessary to increase the buffer size to avoid having frames dropped due -to insufficient space. - -========== ========== ======== ===== -Alternate bytes/ms 15fps 30fps -========== ========== ======== ===== - 2 128 8533 4267 - 3 384 25600 12800 - 4 640 42667 21333 - 5 768 51200 25600 - 6 896 59733 29867 - 7 1023 68200 34100 -========== ========== ======== ===== - -Table: Image size(bytes) - - -How many buffers should I use? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For normal streaming, 3 should give the best results. With only 2, -it is possible for the camera to finish sending one image just after a -program has started reading the other. If this happens, the driver must drop -a frame. The exception to this is if you have a heavily loaded machine. In -this case use 2 buffers. You are probably not reading at the full frame rate. -If the camera can send multiple images before a read finishes, it could -overwrite the third buffer before the read finishes, leading to a corrupt -image. Single and double buffering have extra checks to avoid overwriting. - -Using the camera -~~~~~~~~~~~~~~~~ - -We are providing a modified gqcam application to view the output. In -order to avoid confusion, here it is called mview. There is also the qx5view -program which can also control the lights on the qx5 microscope. MJPEG Tools -(http://mjpeg.sourceforge.net) can also be used to record from the camera. diff --git a/Documentation/admin-guide/media/dvb-drivers.rst b/Documentation/admin-guide/media/dvb-drivers.rst index 8df637c375f9..66fa4edd0606 100644 --- a/Documentation/admin-guide/media/dvb-drivers.rst +++ b/Documentation/admin-guide/media/dvb-drivers.rst @@ -13,4 +13,3 @@ Digital TV driver-specific documentation opera-firmware technisat ttusb-dec - zr364xx diff --git a/Documentation/admin-guide/media/meye.rst b/Documentation/admin-guide/media/meye.rst deleted file mode 100644 index 9098a1e65f8b..000000000000 --- a/Documentation/admin-guide/media/meye.rst +++ /dev/null @@ -1,93 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. include:: <isonum.txt> - -Vaio Picturebook Motion Eye Camera Driver -========================================= - -Copyright |copy| 2001-2004 Stelian Pop <stelian@popies.net> - -Copyright |copy| 2001-2002 AlcĂ´ve <www.alcove.com> - -Copyright |copy| 2000 Andrew Tridgell <tridge@samba.org> - -This driver enable the use of video4linux compatible applications with the -Motion Eye camera. This driver requires the "Sony Laptop Extras" driver (which -can be found in the "Misc devices" section of the kernel configuration utility) -to be compiled and installed (using its "camera=1" parameter). - -It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480. - -Grabbing is supported in packed YUV colorspace only. - -MJPEG hardware grabbing is supported via a private API (see below). - -Hardware supported ------------------- - -This driver supports the 'second' version of the MotionEye camera :) - -The first version was connected directly on the video bus of the Neomagic -video card and is unsupported. - -The second one, made by Kawasaki Steel is fully supported by this -driver (PCI vendor/device is 0x136b/0xff01) - -The third one, present in recent (more or less last year) Picturebooks -(C1M* models), is not supported. The manufacturer has given the specs -to the developers under a NDA (which allows the development of a GPL -driver however), but things are not moving very fast (see -http://r-engine.sourceforge.net/) (PCI vendor/device is 0x10cf/0x2011). - -There is a forth model connected on the USB bus in TR1* Vaio laptops. -This camera is not supported at all by the current driver, in fact -little information if any is available for this camera -(USB vendor/device is 0x054c/0x0107). - -Driver options --------------- - -Several options can be passed to the meye driver using the standard -module argument syntax (<param>=<value> when passing the option to the -module or meye.<param>=<value> on the kernel boot line when meye is -statically linked into the kernel). Those options are: - -.. code-block:: none - - gbuffers: number of capture buffers, default is 2 (32 max) - - gbufsize: size of each capture buffer, default is 614400 - - video_nr: video device to register (0 = /dev/video0, etc) - -Module use ----------- - -In order to automatically load the meye module on use, you can put those lines -in your /etc/modprobe.d/meye.conf file: - -.. code-block:: none - - alias char-major-81 videodev - alias char-major-81-0 meye - options meye gbuffers=32 - -Usage: ------- - -.. code-block:: none - - xawtv >= 3.49 (<http://bytesex.org/xawtv/>) - for display and uncompressed video capture: - - xawtv -c /dev/video0 -geometry 640x480 - or - xawtv -c /dev/video0 -geometry 320x240 - - motioneye (<http://popies.net/meye/>) - for getting ppm or jpg snapshots, mjpeg video - -Bugs / Todo ------------ - -- 'motioneye' still uses the meye private v4l1 API extensions. diff --git a/Documentation/admin-guide/media/other-usb-cardlist.rst b/Documentation/admin-guide/media/other-usb-cardlist.rst index bbfdb1389c18..fb88db50e861 100644 --- a/Documentation/admin-guide/media/other-usb-cardlist.rst +++ b/Documentation/admin-guide/media/other-usb-cardlist.rst @@ -14,8 +14,6 @@ dvb-as102 nBox DVB-T Dongle 0b89:0007 dvb-as102 Sky IT Digital Key (green led) 2137:0001 b2c2-flexcop-usb Technisat/B2C2 FlexCop II/IIb/III 0af7:0101 Digital TV -cpia2 Vision's CPiA2 cameras 0553:0100, 0553:0140, - such as the Digital Blue QX5 0553:0151 go7007 WIS GO7007 MPEG encoder 1943:a250, 093b:a002, 093b:a004, 0eb1:6666, 0eb1:6668 @@ -66,7 +64,6 @@ pwc Visionite VCS-UC300 0d81:1900 pwc Visionite VCS-UM100 0d81:1910 s2255drv Sensoray 2255 1943:2255, 1943:2257 stk1160 STK1160 USB video capture dongle 05e1:0408 -stkwebcam Syntek DC1125 174f:a311, 05e1:0501 dvb-ttusb-budget Technotrend/Hauppauge Nova-USB devices 0b48:1003, 0b48:1004, 0b48:1005 dvb-ttusb_dec Technotrend/Hauppauge MPEG decoder 0b48:1006 @@ -78,15 +75,4 @@ dvb-ttusb_dec Technotrend/Hauppauge MPEG decoder DEC2540-t 0b48:1009 usbtv Fushicai USBTV007 Audio-Video Grabber 1b71:3002, 1f71:3301, 1f71:3306 -zr364xx USB ZR364XX Camera 08ca:0109, 041e:4024, - 0d64:0108, 0546:3187, - 0d64:3108, 0595:4343, - 0bb0:500d, 0feb:2004, - 055f:b500, 08ca:2062, - 052b:1a18, 04c8:0729, - 04f2:a208, 0784:0040, - 06d6:0034, 0a17:0062, - 06d6:003b, 0a17:004e, - 041e:405d, 08ca:2102, - 06d6:003d ================ ====================================== ===================== diff --git a/Documentation/admin-guide/media/pci-cardlist.rst b/Documentation/admin-guide/media/pci-cardlist.rst index f4d670e632f8..42528795d4da 100644 --- a/Documentation/admin-guide/media/pci-cardlist.rst +++ b/Documentation/admin-guide/media/pci-cardlist.rst @@ -77,7 +77,6 @@ ipu3-cio2 Intel ipu3-cio2 driver ivtv Conexant cx23416/cx23415 MPEG encoder/decoder ivtvfb Conexant cx23415 framebuffer mantis MANTIS based cards -meye Sony Vaio Picturebook Motion Eye mxb Siemens-Nixdorf 'Multimedia eXtension Board' netup-unidvb NetUP Universal DVB card ngene Micronas nGene diff --git a/Documentation/admin-guide/media/platform-cardlist.rst b/Documentation/admin-guide/media/platform-cardlist.rst index 8ef57cd13dec..1230ae4037ad 100644 --- a/Documentation/admin-guide/media/platform-cardlist.rst +++ b/Documentation/admin-guide/media/platform-cardlist.rst @@ -30,7 +30,6 @@ exynos-fimc-is EXYNOS4x12 FIMC-IS (Imaging Subsystem) exynos-fimc-lite EXYNOS FIMC-LITE camera interface exynos-gsc Samsung Exynos G-Scaler exy Samsung S5P/EXYNOS4 SoC series Camera Subsystem -fsl-viu Freescale VIU imx-pxp i.MX Pixel Pipeline (PXP) isdf TI DM365 ISIF video capture mmp_camera Marvell Armada 610 integrated camera controller diff --git a/Documentation/admin-guide/media/tm6000-cardlist.rst b/Documentation/admin-guide/media/tm6000-cardlist.rst deleted file mode 100644 index 6d2769c0f4d8..000000000000 --- a/Documentation/admin-guide/media/tm6000-cardlist.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -TM6000 cards list -================= - -.. tabularcolumns:: |p{1.4cm}|p{11.1cm}|p{4.2cm}| - -.. flat-table:: - :header-rows: 1 - :widths: 2 19 18 - :stub-columns: 0 - - * - Card number - - Card name - - USB IDs - - * - 0 - - Unknown tm6000 video grabber - - - - * - 1 - - Generic tm5600 board - - 6000:0001 - - * - 2 - - Generic tm6000 board - - - - * - 3 - - Generic tm6010 board - - 6000:0002 - - * - 4 - - 10Moons UT 821 - - - - * - 5 - - 10Moons UT 330 - - - - * - 6 - - ADSTECH Dual TV USB - - 06e1:f332 - - * - 7 - - Freecom Hybrid Stick / Moka DVB-T Receiver Dual - - 14aa:0620 - - * - 8 - - ADSTECH Mini Dual TV USB - - 06e1:b339 - - * - 9 - - Hauppauge WinTV HVR-900H / WinTV USB2-Stick - - 2040:6600, 2040:6601, 2040:6610, 2040:6611 - - * - 10 - - Beholder Wander DVB-T/TV/FM USB2.0 - - 6000:dec0 - - * - 11 - - Beholder Voyager TV/FM USB2.0 - - 6000:dec1 - - * - 12 - - Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick - - 0ccd:0086, 0ccd:00A5 - - * - 13 - - Twinhan TU501(704D1) - - 13d3:3240, 13d3:3241, 13d3:3243, 13d3:3264 - - * - 14 - - Beholder Wander Lite DVB-T/TV/FM USB2.0 - - 6000:dec2 - - * - 15 - - Beholder Voyager Lite TV/FM USB2.0 - - 6000:dec3 - - * - 16 - - Terratec Grabster AV 150/250 MX - - 0ccd:0079 diff --git a/Documentation/admin-guide/media/usb-cardlist.rst b/Documentation/admin-guide/media/usb-cardlist.rst index 1e96f928e0af..5f5ab0723e48 100644 --- a/Documentation/admin-guide/media/usb-cardlist.rst +++ b/Documentation/admin-guide/media/usb-cardlist.rst @@ -43,7 +43,6 @@ Driver Name airspy AirSpy au0828 Auvitek AU0828 b2c2-flexcop-usb Technisat/B2C2 Air/Sky/Cable2PC USB -cpia2 CPiA2 Video For Linux cx231xx Conexant cx231xx USB video capture dvb-as102 Abilis AS102 DVB receiver dvb-ttusb-budget Technotrend/Hauppauge Nova - USB devices @@ -93,15 +92,10 @@ pwc USB Philips Cameras s2250 Sensoray 2250/2251 s2255drv USB Sensoray 2255 video capture device smsusb Siano SMS1xxx based MDTV receiver -stkwebcam USB Syntek DC1125 Camera -tm6000-alsa TV Master TM5600/6000/6010 audio -tm6000-dvb DVB Support for tm6000 based TV cards -tm6000 TV Master TM5600/6000/6010 driver ttusb_dec Technotrend/Hauppauge USB DEC devices usbtv USBTV007 video capture uvcvideo USB Video Class (UVC) zd1301 ZyDAS ZD1301 -zr364xx USB ZR364XX Camera ====================== ========================================================= .. toctree:: @@ -110,7 +104,6 @@ zr364xx USB ZR364XX Camera au0828-cardlist cx231xx-cardlist em28xx-cardlist - tm6000-cardlist siano-cardlist gspca-cardlist diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst index 734e18c310bd..1c41f87c3917 100644 --- a/Documentation/admin-guide/media/v4l-drivers.rst +++ b/Documentation/admin-guide/media/v4l-drivers.rst @@ -11,14 +11,12 @@ Video4Linux (V4L) driver-specific documentation bttv cafe_ccic - cpia2 cx88 fimc imx imx7 ipu3 ivtv - meye omap3isp omap4_camera philips diff --git a/Documentation/admin-guide/media/zr364xx.rst b/Documentation/admin-guide/media/zr364xx.rst deleted file mode 100644 index 7291e54b8be3..000000000000 --- a/Documentation/admin-guide/media/zr364xx.rst +++ /dev/null @@ -1,102 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -Zoran 364xx based USB webcam module -=================================== - -site: http://royale.zerezo.com/zr364xx/ - -mail: royale@zerezo.com - - -Introduction ------------- - - -This brings support under Linux for the Aiptek PocketDV 3300 and similar -devices in webcam mode. If you just want to get on your PC the pictures -and movies on the camera, you should use the usb-storage module instead. - -The driver works with several other cameras in webcam mode (see the list -below). - -Possible chipsets are : ZR36430 (ZR36430BGC) and -maybe ZR36431, ZR36440, ZR36442... - -You can try the experience changing the vendor/product ID values (look -at the source code). - -You can get these values by looking at /var/log/messages when you plug -your camera, or by typing : cat /sys/kernel/debug/usb/devices. - - -Install -------- - -In order to use this driver, you must compile it with your kernel, -with the following config options:: - - ./scripts/config -e USB - ./scripts/config -m MEDIA_SUPPORT - ./scripts/config -e MEDIA_USB_SUPPORT - ./scripts/config -e MEDIA_CAMERA_SUPPORT - ./scripts/config -m USB_ZR364XX - -Usage ------ - -modprobe zr364xx debug=X mode=Y - -- debug : set to 1 to enable verbose debug messages -- mode : 0 = 320x240, 1 = 160x120, 2 = 640x480 - -You can then use the camera with V4L2 compatible applications, for -example Ekiga. - -To capture a single image, try this: dd if=/dev/video0 of=test.jpg bs=1M -count=1 - -links ------ - -http://mxhaard.free.fr/ (support for many others cams including some Aiptek PocketDV) -http://www.harmwal.nl/pccam880/ (this project also supports cameras based on this chipset) - -Supported devices ------------------ - -====== ======= ============== ==================== -Vendor Product Distributor Model -====== ======= ============== ==================== -0x08ca 0x0109 Aiptek PocketDV 3300 -0x08ca 0x0109 Maxell Maxcam PRO DV3 -0x041e 0x4024 Creative PC-CAM 880 -0x0d64 0x0108 Aiptek Fidelity 3200 -0x0d64 0x0108 Praktica DCZ 1.3 S -0x0d64 0x0108 Genius Digital Camera (?) -0x0d64 0x0108 DXG Technology Fashion Cam -0x0546 0x3187 Polaroid iON 230 -0x0d64 0x3108 Praktica Exakta DC 2200 -0x0d64 0x3108 Genius G-Shot D211 -0x0595 0x4343 Concord Eye-Q Duo 1300 -0x0595 0x4343 Concord Eye-Q Duo 2000 -0x0595 0x4343 Fujifilm EX-10 -0x0595 0x4343 Ricoh RDC-6000 -0x0595 0x4343 Digitrex DSC 1300 -0x0595 0x4343 Firstline FDC 2000 -0x0bb0 0x500d Concord EyeQ Go Wireless -0x0feb 0x2004 CRS Electronic 3.3 Digital Camera -0x0feb 0x2004 Packard Bell DSC-300 -0x055f 0xb500 Mustek MDC 3000 -0x08ca 0x2062 Aiptek PocketDV 5700 -0x052b 0x1a18 Chiphead Megapix V12 -0x04c8 0x0729 Konica Revio 2 -0x04f2 0xa208 Creative PC-CAM 850 -0x0784 0x0040 Traveler Slimline X5 -0x06d6 0x0034 Trust Powerc@m 750 -0x0a17 0x0062 Pentax Optio 50L -0x06d6 0x003b Trust Powerc@m 970Z -0x0a17 0x004e Pentax Optio 50 -0x041e 0x405d Creative DiVi CAM 516 -0x08ca 0x2102 Aiptek DV T300 -0x06d6 0x003d Trust Powerc@m 910Z -====== ======= ============== ==================== diff --git a/Documentation/devicetree/bindings/media/cec-gpio.txt b/Documentation/devicetree/bindings/media/cec-gpio.txt deleted file mode 100644 index 47e8d73d32a3..000000000000 --- a/Documentation/devicetree/bindings/media/cec-gpio.txt +++ /dev/null @@ -1,42 +0,0 @@ -* HDMI CEC GPIO driver - -The HDMI CEC GPIO module supports CEC implementations where the CEC line -is hooked up to a pull-up GPIO line and - optionally - the HPD line is -hooked up to another GPIO line. - -Please note: the maximum voltage for the CEC line is 3.63V, for the HPD and -5V lines it is 5.3V. So you may need some sort of level conversion circuitry -when connecting them to a GPIO line. - -Required properties: - - compatible: value must be "cec-gpio". - - cec-gpios: gpio that the CEC line is connected to. The line should be - tagged as open drain. - -If the CEC line is associated with an HDMI receiver/transmitter, then the -following property is also required: - - - hdmi-phandle - phandle to the HDMI controller, see also cec.txt. - -If the CEC line is not associated with an HDMI receiver/transmitter, then -the following property is optional and can be used for debugging HPD changes: - - - hpd-gpios: gpio that the HPD line is connected to. - -This property is optional and can be used for debugging changes on the 5V line: - - - v5-gpios: gpio that the 5V line is connected to. - -Example for the Raspberry Pi 3 where the CEC line is connected to -pin 26 aka BCM7 aka CE1 on the GPIO pin header, the HPD line is -connected to pin 11 aka BCM17 and the 5V line is connected to pin -15 aka BCM22 (some level shifter is needed for the HPD and 5V lines!): - -#include <dt-bindings/gpio/gpio.h> - -cec-gpio { - compatible = "cec-gpio"; - cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; - hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/media/cec.txt b/Documentation/devicetree/bindings/media/cec.txt deleted file mode 100644 index 22d7aae3d3d7..000000000000 --- a/Documentation/devicetree/bindings/media/cec.txt +++ /dev/null @@ -1,8 +0,0 @@ -Common bindings for HDMI CEC adapters - -- hdmi-phandle: phandle to the HDMI controller. - -- needs-hpd: if present the CEC support is only available when the HPD - is high. Some boards only let the CEC pin through if the HPD is high, - for example if there is a level converter that uses the HPD to power - up or down. diff --git a/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml index 8d844f4312d1..b1fab53418f9 100644 --- a/Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml +++ b/Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/media/amlogic,meson-gx-ao-cec.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/media/cec/amlogic,meson-gx-ao-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson AO-CEC Controller @@ -33,11 +33,8 @@ properties: interrupts: maxItems: 1 - hdmi-phandle: - description: phandle to the HDMI controller - $ref: /schemas/types.yaml#/definitions/phandle - allOf: + - $ref: cec-common.yaml# - if: properties: compatible: @@ -81,7 +78,7 @@ required: - clocks - clock-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/media/cec/cec-common.yaml b/Documentation/devicetree/bindings/media/cec/cec-common.yaml new file mode 100644 index 000000000000..af6ee5f1c73f --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/cec-common.yaml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/cec-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HDMI CEC Adapters Common Properties + +maintainers: + - Hans Verkuil <hverkuil@xs4all.nl> + +properties: + $nodename: + pattern: "^cec(@[0-9a-f]+|-[0-9]+)?$" + + hdmi-phandle: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the HDMI controller. + + needs-hpd: + type: boolean + description: + The CEC support is only available when the HPD is high. Some boards only + let the CEC pin through if the HPD is high, for example if there is a + level converter that uses the HPD to power up or down. + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml new file mode 100644 index 000000000000..64d7ec057672 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/cec-gpio.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/cec-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HDMI CEC GPIO + +maintainers: + - Hans Verkuil <hverkuil-cisco@xs4all.nl> + +description: | + The HDMI CEC GPIO module supports CEC implementations where the CEC line is + hooked up to a pull-up GPIO line and - optionally - the HPD line is hooked up + to another GPIO line. + + Please note:: the maximum voltage for the CEC line is 3.63V, for the HPD and + 5V lines it is 5.3V. So you may need some sort of level conversion + circuitry when connecting them to a GPIO line. + +properties: + compatible: + const: cec-gpio + + cec-gpios: + maxItems: 1 + description: + GPIO that the CEC line is connected to. The line should be tagged as open + drain. + + hpd-gpios: + maxItems: 1 + description: + GPIO that the HPD line is connected to. Used for debugging HPD changes + when the CEC line is not associated with an HDMI receiver/transmitter. + + v5-gpios: + maxItems: 1 + description: + GPIO that the 5V line is connected to. Used for debugging changes on the + 5V line. + +required: + - compatible + - cec-gpios + +allOf: + - $ref: cec-common.yaml# + - if: + required: + - hdmi-phandle + then: + properties: + hpd-gpios: false + + - if: + required: + - hpd-gpios + then: + properties: + hdmi-phandle: false + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + cec { + compatible = "cec-gpio"; + cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml b/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml new file mode 100644 index 000000000000..369c48fd9bf9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/nvidia,tegra114-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra HDMI CEC + +maintainers: + - Hans Verkuil <hverkuil-cisco@xs4all.nl> + +allOf: + - $ref: cec-common.yaml# + +properties: + compatible: + enum: + - nvidia,tegra114-cec + - nvidia,tegra124-cec + - nvidia,tegra210-cec + + clocks: + maxItems: 1 + + clock-names: + items: + - const: cec + + interrupts: + maxItems: 1 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - hdmi-phandle + - interrupts + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/tegra124-car.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + cec@70015000 { + compatible = "nvidia,tegra124-cec"; + reg = <0x70015000 0x00001000>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&tegra_car TEGRA124_CLK_CEC>; + clock-names = "cec"; + status = "disabled"; + hdmi-phandle = <&hdmi>; + }; diff --git a/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml b/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml new file mode 100644 index 000000000000..016c8a77c1a6 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/samsung,s5p-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung S5PV210 and Exynos HDMI CEC + +maintainers: + - Krzysztof Kozlowski <krzk@kernel.org> + - Marek Szyprowski <m.szyprowski@samsung.com> + +allOf: + - $ref: cec-common.yaml# + +properties: + compatible: + const: samsung,s5p-cec + + clocks: + maxItems: 1 + + clock-names: + items: + - const: hdmicec + + interrupts: + maxItems: 1 + + samsung,syscon-phandle: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to PMU system controller interface + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - hdmi-phandle + - interrupts + - samsung,syscon-phandle + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/exynos5420.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + cec@101b0000 { + compatible = "samsung,s5p-cec"; + reg = <0x101B0000 0x200>; + + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; + hdmi-phandle = <&hdmi>; + needs-hpd; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; + samsung,syscon-phandle = <&pmu_system_controller>; + }; diff --git a/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml b/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml new file mode 100644 index 000000000000..aeddf16ed339 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/st,stih-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STIH4xx HDMI CEC + +maintainers: + - Alain Volmat <alain.volmat@foss.st.com> + +allOf: + - $ref: cec-common.yaml# + +properties: + compatible: + const: st,stih-cec + + clocks: + maxItems: 1 + + clock-names: + items: + - const: cec-clk + + interrupts: + maxItems: 1 + + interrupt-names: + items: + - const: cec-irq + + resets: + maxItems: 1 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - hdmi-phandle + - interrupts + - resets + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/reset/stih407-resets.h> + + cec@94a087c { + compatible = "st,stih-cec"; + reg = <0x94a087c 0x64>; + + clocks = <&clk_sysin>; + clock-names = "cec-clk"; + hdmi-phandle = <&sti_hdmi>; + interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cec-irq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cec0_default>; + resets = <&softreset STIH407_LPM_SOFTRESET>; + }; diff --git a/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml b/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml new file mode 100644 index 000000000000..2314a9a14650 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec/st,stm32-cec.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cec/st,stm32-cec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32 CEC + +maintainers: + - Yannick Fertre <yannick.fertre@foss.st.com> + +properties: + compatible: + const: st,stm32-cec + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Module Clock + - description: Bus Clock + + clock-names: + items: + - const: cec + - const: hdmi-cec + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/stm32mp1-clks.h> + cec: cec@40006c00 { + compatible = "st,stm32-cec"; + reg = <0x40006c00 0x400>; + interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc CEC_K>, <&clk_lse>; + clock-names = "cec", "hdmi-cec"; + }; + +... diff --git a/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml b/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml new file mode 100644 index 000000000000..84a5e894ace4 --- /dev/null +++ b/Documentation/devicetree/bindings/media/fsl,imx6ull-pxp.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/fsl,imx6ull-pxp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale Pixel Pipeline + +maintainers: + - Philipp Zabel <p.zabel@pengutronix.de> + - Michael Tretter <m.tretter@pengutronix.de> + +description: + The Pixel Pipeline (PXP) is a memory-to-memory graphics processing engine + that supports scaling, colorspace conversion, alpha blending, rotation, and + pixel conversion via lookup table. Different versions are present on various + i.MX SoCs from i.MX23 to i.MX7. + +properties: + compatible: + oneOf: + - enum: + - fsl,imx6ul-pxp + - fsl,imx6ull-pxp + - fsl,imx7d-pxp + - items: + - enum: + - fsl,imx6sll-pxp + - fsl,imx6sx-pxp + - const: fsl,imx6ull-pxp + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + + clocks: + maxItems: 1 + + clock-names: + const: axi + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx6sx-pxp + - fsl,imx6ul-pxp + then: + properties: + interrupts: + maxItems: 1 + else: + properties: + interrupts: + minItems: 2 + maxItems: 2 + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/imx6ul-clock.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + pxp: pxp@21cc000 { + compatible = "fsl,imx6ull-pxp"; + reg = <0x021cc000 0x4000>; + interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "axi"; + clocks = <&clks IMX6UL_CLK_PXP>; + }; diff --git a/Documentation/devicetree/bindings/media/fsl-pxp.txt b/Documentation/devicetree/bindings/media/fsl-pxp.txt deleted file mode 100644 index f8090e06530d..000000000000 --- a/Documentation/devicetree/bindings/media/fsl-pxp.txt +++ /dev/null @@ -1,26 +0,0 @@ -Freescale Pixel Pipeline -======================== - -The Pixel Pipeline (PXP) is a memory-to-memory graphics processing engine -that supports scaling, colorspace conversion, alpha blending, rotation, and -pixel conversion via lookup table. Different versions are present on various -i.MX SoCs from i.MX23 to i.MX7. - -Required properties: -- compatible: should be "fsl,<soc>-pxp", where SoC can be one of imx23, imx28, - imx6dl, imx6sl, imx6sll, imx6ul, imx6sx, imx6ull, or imx7d. -- reg: the register base and size for the device registers -- interrupts: the PXP interrupt, two interrupts for imx6ull and imx7d. -- clock-names: should be "axi" -- clocks: the PXP AXI clock - -Example: - -pxp@21cc000 { - compatible = "fsl,imx6ull-pxp"; - reg = <0x021cc000 0x4000>; - interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>; - clock-names = "axi"; - clocks = <&clks IMX6UL_CLK_PXP>; -}; diff --git a/Documentation/devicetree/bindings/media/i2c/ak7375.txt b/Documentation/devicetree/bindings/media/i2c/ak7375.txt deleted file mode 100644 index aa3e24b41241..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/ak7375.txt +++ /dev/null @@ -1,8 +0,0 @@ -Asahi Kasei Microdevices AK7375 voice coil lens driver - -AK7375 is a camera voice coil lens. - -Mandatory properties: - -- compatible: "asahi-kasei,ak7375" -- reg: I2C slave address diff --git a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml new file mode 100644 index 000000000000..22a810fc7222 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/asahi-kasei,ak7375.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Asahi Kasei Microdevices AK7375 voice coil lens actuator + +maintainers: + - Tianshu Qiu <tian.shu.qiu@intel.com> + +description: + AK7375 is a voice coil motor (VCM) camera lens actuator that + is controlled over I2C. + +properties: + compatible: + const: asahi-kasei,ak7375 + + reg: + maxItems: 1 + + vdd-supply: + description: VDD supply + + vio-supply: + description: I/O pull-up supply + +required: + - compatible + - reg + - vdd-supply + - vio-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ak7375: camera-lens@c { + compatible = "asahi-kasei,ak7375"; + reg = <0x0c>; + + vdd-supply = <&vreg_l23a_2p8>; + vio-supply = <&vreg_lvs1a_1p8>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml b/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml index 63e5b89d2e0b..af8ada55b3f2 100644 --- a/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml +++ b/Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml @@ -13,6 +13,9 @@ description: The Chrontel CH7322 is a discrete HDMI-CEC controller. It is programmable through I2C and drives a single CEC line. +allOf: + - $ref: /schemas/media/cec/cec-common.yaml# + properties: compatible: const: chrontel,ch7322 @@ -40,16 +43,12 @@ properties: if in auto mode. maxItems: 1 - # see ../cec.txt - hdmi-phandle: - description: phandle to the HDMI controller - required: - compatible - reg - interrupts -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -58,7 +57,7 @@ examples: i2c { #address-cells = <1>; #size-cells = <0>; - ch7322@75 { + cec@75 { compatible = "chrontel,ch7322"; reg = <0x75>; interrupts = <47 IRQ_TYPE_EDGE_RISING>; diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml index 90315e217003..0c4213adbf6a 100644 --- a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml +++ b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml @@ -39,7 +39,7 @@ properties: maxItems: 1 poc-supply: - description: Regulator providing Power over Coax to the cameras + description: Regulator providing Power over Coax to all the ports enable-gpios: description: GPIO connected to the \#PWDN pin with inverted polarity @@ -50,6 +50,21 @@ properties: '#gpio-cells': const: 2 + maxim,bus-width: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 24, 27, 32 ] + description: | + The GMSL serial data bus width. This setting is normally controlled by + the BWS pin, but may be overridden with this property. The value must + match the configuration of the remote serializers. + + maxim,i2c-remote-bus-hz: + enum: [ 8470, 28300, 84700, 105000, 173000, 339000, 533000, 837000 ] + default: 105000 + description: | + The I2C clock frequency for the remote I2C buses. The value must match + the configuration of the remote serializers. + maxim,reverse-channel-microvolt: minimum: 30000 maximum: 200000 @@ -182,21 +197,36 @@ properties: additionalProperties: false +patternProperties: + "^port[0-3]-poc-supply$": + description: Regulator providing Power over Coax for a particular port + required: - compatible - reg - ports - i2c-mux -# If 'maxim,gpio-poc' is present, then 'poc-supply' and 'gpio-controller' -# are not allowed. -if: - required: - - maxim,gpio-poc -then: - properties: - poc-supply: false - gpio-controller: false +allOf: + # Only one way of specifying power supplies is allowed: 'maxim,gpio-poc', + # 'poc-supply' or per-port poc-supply. Additionally, if 'maxim,gpio-poc' is + # present, then 'gpio-controller' isn't allowed. + - if: + required: + - maxim,gpio-poc + then: + properties: + poc-supply: false + gpio-controller: false + patternProperties: + "^port[0-3]-poc-supply$": false + + - if: + required: + - poc-supply + then: + patternProperties: + "^port[0-3]-poc-supply$": false additionalProperties: false @@ -219,6 +249,7 @@ examples: gpio-controller; #gpio-cells = <2>; + maxim,i2c-remote-bus-hz = <339000>; maxim,reverse-channel-microvolt = <170000>; ports { diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml new file mode 100644 index 000000000000..6e089fe1d613 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov5670.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV5670 5 Megapixels raw image sensor + +maintainers: + - Jacopo Mondi <jacopo.mondi@ideasonboard.com> + +description: |- + The OV5670 is a 5 Megapixels raw image sensor which provides images in 10-bits + RAW BGGR Bayer format on a 2 data lanes MIPI CSI-2 serial interface and is + controlled through an I2C compatible control bus. + +properties: + compatible: + const: ovti,ov5670 + + reg: + maxItems: 1 + + clocks: + description: System clock. From 6 to 27 MHz. + maxItems: 1 + + powerdown-gpios: + description: Reference to the GPIO connected to the PWDNB pin. Active low. + + reset-gpios: + description: Reference to the GPIO connected to the XSHUTDOWN pin. Active low. + maxItems: 1 + + avdd-supply: + description: Analog circuit power. Typically 2.8V. + + dvdd-supply: + description: Digital circuit power. Typically 1.2V. + + dovdd-supply: + description: Digital I/O circuit power. Typically 2.8V or 1.8V. + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + additionalProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 2 + items: + enum: [1, 2] + + clock-noncontinuous: true + remote-endpoint: true + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5670: sensor@36 { + compatible = "ovti,ov5670"; + reg = <0x36>; + + clocks = <&sensor_xclk>; + + port { + ov5670_ep: endpoint { + remote-endpoint = <&csi_ep>; + data-lanes = <1 2>; + clock-noncontinuous; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml new file mode 100644 index 000000000000..ad07204057f9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2022 Theobroma Systems Design und Consulting GmbH +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov5675.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV5675 CMOS Sensor + +maintainers: + - Quentin Schulz <quentin.schulz@theobroma-systems.com> + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +description: | + The Omnivision OV5675 is a high performance, 1/5-inch, 5 megapixel, CMOS + image sensor that delivers 2592x1944 at 30fps. It provides full-frame, + sub-sampled, and windowed 10-bit MIPI images in various formats via the + Serial Camera Control Bus (SCCB) interface. + + This chip is programmable through I2C and two-wire SCCB. The sensor output + is available via CSI-2 serial data output (up to 2-lane). + +properties: + compatible: + const: ovti,ov5675 + + reg: + maxItems: 1 + + clocks: + description: + System input clock (aka XVCLK). From 6 to 27 MHz. + maxItems: 1 + + dovdd-supply: + description: + Digital I/O voltage supply, 1.8 volts. + + avdd-supply: + description: + Analog voltage supply, 2.8 volts. + + dvdd-supply: + description: + Digital core voltage supply, 1.2 volts. + + reset-gpios: + description: + The phandle and specifier for the GPIO that controls sensor reset. + This corresponds to the hardware pin XSHUTDN which is physically + active low. + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 2 + + # Supports max data transfer of 900 Mbps per lane + link-frequencies: true + +required: + - compatible + - reg + - clocks + - dovdd-supply + - avdd-supply + - dvdd-supply + - port + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/px30-cru.h> + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/pinctrl/rockchip.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov5675: camera@36 { + compatible = "ovti,ov5675"; + reg = <0x36>; + + reset-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&cif_clkout_m0>; + + clocks = <&cru SCLK_CIF_OUT>; + assigned-clocks = <&cru SCLK_CIF_OUT>; + assigned-clock-rates = <19200000>; + + avdd-supply = <&vcc_1v8>; + dvdd-supply = <&vcc_1v2>; + dovdd-supply = <&vcc_2v8>; + + rotation = <90>; + orientation = <0>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <450000000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml new file mode 100644 index 000000000000..a65f921ec0fd --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov8858.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV8858 Image Sensor + +maintainers: + - Jacopo Mondi <jacopo.mondi@ideasonboard.com> + - Nicholas Roth <nicholas@rothemail.net> + +description: | + The OmniVision OV8858 is a color CMOS 8 Megapixels (3264x2448) image sensor + controlled through an I2C-compatible SCCB bus. The sensor transmits images + on a MIPI CSI-2 output interface with up to 4 data lanes. + +properties: + compatible: + const: ovti,ov8858 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: XVCLK external clock + + clock-names: + const: xvclk + + dvdd-supply: + description: Digital Domain Power Supply + + avdd-supply: + description: Analog Domain Power Supply + + dovdd-supply: + description: I/O Domain Power Supply + + powerdown-gpios: + description: PWDNB powerdown GPIO (active low) + + reset-gpios: + maxItems: 1 + description: XSHUTDN reset GPIO (active low) + + port: + description: MIPI CSI-2 transmitter port + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/pinctrl/rockchip.h> + #include <dt-bindings/clock/rk3399-cru.h> + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov8858: camera@36 { + compatible = "ovti,ov8858"; + reg = <0x36>; + + clocks = <&cru SCLK_CIF_OUT>; + clock-names = "xvclk"; + assigned-clocks = <&cru SCLK_CIF_OUT>; + assigned-clock-rates = <24000000>; + + dovdd-supply = <&vcc1v8_dvp>; + + reset-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_LOW>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1 2 3 4>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml new file mode 100644 index 000000000000..65ad9c100e45 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx296.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX296 1/2.8-Inch CMOS Image Sensor + +maintainers: + - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + - Laurent Pinchart <laurent.pinchart@ideasonboard.com> + +description: |- + The Sony IMX296 is a 1/2.9-Inch active pixel type CMOS Solid-state image + sensor with square pixel array and 1.58 M effective pixels. This chip + features a global shutter with variable charge-integration time. It is + programmable through I2C and 4-wire interfaces. The sensor output is + available via CSI-2 serial data output (1 Lane). + +properties: + compatible: + enum: + - sony,imx296 + - sony,imx296ll + - sony,imx296lq + description: + The IMX296 sensor exists in two different models, a colour variant + (IMX296LQ) and a monochrome variant (IMX296LL). The device exposes the + model through registers, allowing for auto-detection with a common + "sony,imx296" compatible string. However, some camera modules disable the + ability to read the sensor model register, which disables this feature. + In those cases, the exact model needs to be specified as "sony,imx296ll" + or "sony,imx296lq". + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + description: Input clock (37.125 MHz, 54 MHz or 74.25 MHz) + items: + - const: inck + + avdd-supply: + description: Analog power supply (3.3V) + + dvdd-supply: + description: Digital power supply (1.2V) + + ovdd-supply: + description: Interface power supply (1.8V) + + reset-gpios: + description: Sensor reset (XCLR) GPIO + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - reg + - clocks + - clock-names + - avdd-supply + - dvdd-supply + - ovdd-supply + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imx296: camera-sensor@1a { + compatible = "sony,imx296"; + reg = <0x1a>; + + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_default>; + + clocks = <&gcc 90>; + clock-names = "inck"; + + avdd-supply = <&camera_vdda_3v3>; + dvdd-supply = <&camera_vddd_1v2>; + ovdd-supply = <&camera_vddo_1v8>; + + reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>; + + port { + imx296_ep: endpoint { + remote-endpoint = <&csiphy0_ep>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml new file mode 100644 index 000000000000..ffccf5f3c9e3 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx415.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX415 CMOS Image Sensor + +maintainers: + - Michael Riesch <michael.riesch@wolfvision.net> + +description: |- + The Sony IMX415 is a diagonal 6.4 mm (Type 1/2.8) CMOS active pixel type + solid-state image sensor with a square pixel array and 8.46 M effective + pixels. This chip operates with analog 2.9 V, digital 1.1 V, and interface + 1.8 V triple power supply, and has low power consumption. + The IMX415 is programmable through I2C interface. The sensor output is + available via CSI-2 serial data output (two or four lanes). + +allOf: + - $ref: ../video-interface-devices.yaml# + +properties: + compatible: + const: sony,imx415 + + reg: + maxItems: 1 + + clocks: + description: Input clock (24 MHz, 27 MHz, 37.125 MHz, 72 MHz or 74.25 MHz) + maxItems: 1 + + avdd-supply: + description: Analog power supply (2.9 V) + + dvdd-supply: + description: Digital power supply (1.1 V) + + ovdd-supply: + description: Interface power supply (1.8 V) + + reset-gpios: + description: Sensor reset (XCLR) GPIO + maxItems: 1 + + flash-leds: true + + lens-focus: true + + orientation: true + + rotation: true + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + oneOf: + - items: + - const: 1 + - const: 2 + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - avdd-supply + - dvdd-supply + - ovdd-supply + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imx415: camera-sensor@1a { + compatible = "sony,imx415"; + reg = <0x1a>; + avdd-supply = <&vcc2v9_cam>; + clocks = <&clock_cam>; + dvdd-supply = <&vcc1v1_cam>; + lens-focus = <&vcm>; + orientation = <2>; + ovdd-supply = <&vcc1v8_cam>; + reset-gpios = <&gpio_expander 14 GPIO_ACTIVE_LOW>; + rotation = <180>; + + port { + imx415_ep: endpoint { + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <445500000>; + remote-endpoint = <&mipi_in>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml index 4f7b78265336..358019e85d90 100644 --- a/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml +++ b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml @@ -37,6 +37,9 @@ properties: items: - const: mclk + power-domains: + maxItems: 1 + port: $ref: /schemas/graph.yaml#/properties/port @@ -50,6 +53,18 @@ required: additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8mq-csi + - fsl,imx8mm-csi + then: + required: + - power-domains + examples: - | #include <dt-bindings/clock/imx7d-clock.h> diff --git a/Documentation/devicetree/bindings/media/s5p-cec.txt b/Documentation/devicetree/bindings/media/s5p-cec.txt deleted file mode 100644 index e847291d4aff..000000000000 --- a/Documentation/devicetree/bindings/media/s5p-cec.txt +++ /dev/null @@ -1,36 +0,0 @@ -* Samsung HDMI CEC driver - -The HDMI CEC module is present is Samsung SoCs and its purpose is to -handle communication between HDMI connected devices over the CEC bus. - -Required properties: - - compatible : value should be following - "samsung,s5p-cec" - - - reg : Physical base address of the IP registers and length of memory - mapped region. - - - interrupts : HDMI CEC interrupt number to the CPU. - - clocks : from common clock binding: handle to HDMI CEC clock. - - clock-names : from common clock binding: must contain "hdmicec", - corresponding to entry in the clocks property. - - samsung,syscon-phandle - phandle to the PMU system controller - - hdmi-phandle - phandle to the HDMI controller, see also cec.txt. - -Optional: - - needs-hpd : if present the CEC support is only available when the HPD - is high. See cec.txt for more details. - -Example: - -hdmicec: cec@100b0000 { - compatible = "samsung,s5p-cec"; - reg = <0x100B0000 0x200>; - interrupts = <0 114 0>; - clocks = <&clock CLK_HDMI_CEC>; - clock-names = "hdmicec"; - samsung,syscon-phandle = <&pmu_system_controller>; - hdmi-phandle = <&hdmi>; - pinctrl-names = "default"; - pinctrl-0 = <&hdmi_cec>; -}; diff --git a/Documentation/devicetree/bindings/media/stih-cec.txt b/Documentation/devicetree/bindings/media/stih-cec.txt deleted file mode 100644 index ece0832fdeaf..000000000000 --- a/Documentation/devicetree/bindings/media/stih-cec.txt +++ /dev/null @@ -1,27 +0,0 @@ -STMicroelectronics STIH4xx HDMI CEC driver - -Required properties: - - compatible : value should be "st,stih-cec" - - reg : Physical base address of the IP registers and length of memory - mapped region. - - clocks : from common clock binding: handle to HDMI CEC clock - - interrupts : HDMI CEC interrupt number to the CPU. - - pinctrl-names: Contains only one value - "default" - - pinctrl-0: Specifies the pin control groups used for CEC hardware. - - resets: Reference to a reset controller - - hdmi-phandle: Phandle to the HDMI controller, see also cec.txt. - -Example for STIH407: - -sti-cec@94a087c { - compatible = "st,stih-cec"; - reg = <0x94a087c 0x64>; - clocks = <&clk_sysin>; - clock-names = "cec-clk"; - interrupts = <GIC_SPI 140 IRQ_TYPE_NONE>; - interrupt-names = "cec-irq"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_cec0_default>; - resets = <&softreset STIH407_LPM_SOFTRESET>; - hdmi-phandle = <&hdmi>; -}; diff --git a/Documentation/devicetree/bindings/media/tegra-cec.txt b/Documentation/devicetree/bindings/media/tegra-cec.txt deleted file mode 100644 index c503f06f3b84..000000000000 --- a/Documentation/devicetree/bindings/media/tegra-cec.txt +++ /dev/null @@ -1,27 +0,0 @@ -* Tegra HDMI CEC hardware - -The HDMI CEC module is present in Tegra SoCs and its purpose is to -handle communication between HDMI connected devices over the CEC bus. - -Required properties: - - compatible : value should be one of the following: - "nvidia,tegra114-cec" - "nvidia,tegra124-cec" - "nvidia,tegra210-cec" - - reg : Physical base address of the IP registers and length of memory - mapped region. - - interrupts : HDMI CEC interrupt number to the CPU. - - clocks : from common clock binding: handle to HDMI CEC clock. - - clock-names : from common clock binding: must contain "cec", - corresponding to the entry in the clocks property. - - hdmi-phandle : phandle to the HDMI controller, see also cec.txt. - -Example: - -cec@70015000 { - compatible = "nvidia,tegra124-cec"; - reg = <0x0 0x70015000 0x0 0x00001000>; - interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&tegra_car TEGRA124_CLK_CEC>; - clock-names = "cec"; -}; diff --git a/Documentation/driver-api/media/drivers/cpia2_devel.rst b/Documentation/driver-api/media/drivers/cpia2_devel.rst deleted file mode 100644 index decaa4768c78..000000000000 --- a/Documentation/driver-api/media/drivers/cpia2_devel.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -The cpia2 driver -================ - -Authors: Peter Pregler <Peter_Pregler@email.com>, -Scott J. Bertin <scottbertin@yahoo.com>, and -Jarl Totland <Jarl.Totland@bdc.no> for the original cpia driver, which -this one was modelled from. - - -Notes to developers -~~~~~~~~~~~~~~~~~~~ - - - This is a driver version stripped of the 2.4 back compatibility - and old MJPEG ioctl API. See cpia2.sf.net for 2.4 support. - -Programmer's overview of cpia2 driver -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Cpia2 is the second generation video coprocessor from VLSI Vision Ltd (now a -division of ST Microelectronics). There are two versions. The first is the -STV0672, which is capable of up to 30 frames per second (fps) in frame sizes -up to CIF, and 15 fps for VGA frames. The STV0676 is an improved version, -which can handle up to 30 fps VGA. Both coprocessors can be attached to two -CMOS sensors - the vvl6410 CIF sensor and the vvl6500 VGA sensor. These will -be referred to as the 410 and the 500 sensors, or the CIF and VGA sensors. - -The two chipsets operate almost identically. The core is an 8051 processor, -running two different versions of firmware. The 672 runs the VP4 video -processor code, the 676 runs VP5. There are a few differences in register -mappings for the two chips. In these cases, the symbols defined in the -header files are marked with VP4 or VP5 as part of the symbol name. - -The cameras appear externally as three sets of registers. Setting register -values is the only way to control the camera. Some settings are -interdependant, such as the sequence required to power up the camera. I will -try to make note of all of these cases. - -The register sets are called blocks. Block 0 is the system block. This -section is always powered on when the camera is plugged in. It contains -registers that control housekeeping functions such as powering up the video -processor. The video processor is the VP block. These registers control -how the video from the sensor is processed. Examples are timing registers, -user mode (vga, qvga), scaling, cropping, framerates, and so on. The last -block is the video compressor (VC). The video stream sent from the camera is -compressed as Motion JPEG (JPEGA). The VC controls all of the compression -parameters. Looking at the file cpia2_registers.h, you can get a full view -of these registers and the possible values for most of them. - -One or more registers can be set or read by sending a usb control message to -the camera. There are three modes for this. Block mode requests a number -of contiguous registers. Random mode reads or writes random registers with -a tuple structure containing address/value pairs. The repeat mode is only -used by VP4 to load a firmware patch. It contains a starting address and -a sequence of bytes to be written into a gpio port. diff --git a/Documentation/driver-api/media/drivers/index.rst b/Documentation/driver-api/media/drivers/index.rst index 3c17d48f83c0..c4123a16b5f9 100644 --- a/Documentation/driver-api/media/drivers/index.rst +++ b/Documentation/driver-api/media/drivers/index.rst @@ -13,7 +13,6 @@ Video4Linux (V4L) drivers :maxdepth: 5 bttv-devel - cpia2_devel cx2341x-devel cx88-devel fimc-devel diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst index 400b8ca29367..2456950ce8ff 100644 --- a/Documentation/driver-api/media/mc-core.rst +++ b/Documentation/driver-api/media/mc-core.rst @@ -232,12 +232,10 @@ prevent link states from being modified during streaming by calling The function will mark all the pads which are part of the pipeline as streaming. -The struct media_pipeline instance pointed to by -the pipe argument will be stored in every pad in the pipeline. -Drivers should embed the struct media_pipeline -in higher-level pipeline structures and can then access the -pipeline through the struct media_pad -pipe field. +The struct media_pipeline instance pointed to by the pipe argument will be +stored in every pad in the pipeline. Drivers should embed the struct +media_pipeline in higher-level pipeline structures and can then access the +pipeline through the struct media_pad pipe field. Calls to :c:func:`media_pipeline_start()` can be nested. The pipeline pointer must be identical for all nested calls to the function. diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst index 8797037c4e2e..602dadaa81d8 100644 --- a/Documentation/driver-api/media/v4l2-subdev.rst +++ b/Documentation/driver-api/media/v4l2-subdev.rst @@ -593,6 +593,14 @@ before calling v4l2_subdev_init_finalize(): This shares the driver's private mutex between the controls and the states. +Streams, multiplexed media pads and internal routing +---------------------------------------------------- + +A subdevice driver can implement support for multiplexed streams by setting +the V4L2_SUBDEV_FL_STREAMS subdev flag and implementing support for +centrally managed subdev active state, routing and stream based +configuration. + V4L2 sub-device functions and data structures --------------------------------------------- diff --git a/Documentation/userspace-api/media/drivers/aspeed-video.rst b/Documentation/userspace-api/media/drivers/aspeed-video.rst index 1b0cb1e3eba8..567387aca6b0 100644 --- a/Documentation/userspace-api/media/drivers/aspeed-video.rst +++ b/Documentation/userspace-api/media/drivers/aspeed-video.rst @@ -23,7 +23,7 @@ proprietary mode. More details on the ASPEED video hardware operations can be found in *chapter 6.2.16 KVM Video Driver* of SDK_User_Guide which available on -AspeedTech-BMC/openbmc/releases. +`github <https://github.com/AspeedTech-BMC/openbmc/releases/>`__. The ASPEED video driver implements the following driver-specific control: diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 915dbf0f4db5..6708d649afd7 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -37,7 +37,6 @@ For more details see the file COPYING in the source distribution of Linux. dw100 imx-uapi max2175 - meye-uapi omap3isp-uapi st-vgxy61 uvcvideo diff --git a/Documentation/userspace-api/media/drivers/meye-uapi.rst b/Documentation/userspace-api/media/drivers/meye-uapi.rst deleted file mode 100644 index 66b1c142f920..000000000000 --- a/Documentation/userspace-api/media/drivers/meye-uapi.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. include:: <isonum.txt> - -Vaio Picturebook Motion Eye Camera Driver -========================================= - -Copyright |copy| 2001-2004 Stelian Pop <stelian@popies.net> - -Copyright |copy| 2001-2002 AlcĂ´ve <www.alcove.com> - -Copyright |copy| 2000 Andrew Tridgell <tridge@samba.org> - -Private API ------------ - -The driver supports frame grabbing with the video4linux API, -so all video4linux tools (like xawtv) should work with this driver. - -Besides the video4linux interface, the driver has a private interface -for accessing the Motion Eye extended parameters (camera sharpness, -agc, video framerate), the snapshot and the MJPEG capture facilities. - -This interface consists of several ioctls (prototypes and structures -can be found in include/linux/meye.h): - -MEYEIOC_G_PARAMS and MEYEIOC_S_PARAMS - Get and set the extended parameters of the motion eye camera. - The user should always query the current parameters with - MEYEIOC_G_PARAMS, change what he likes and then issue the - MEYEIOC_S_PARAMS call (checking for -EINVAL). The extended - parameters are described by the meye_params structure. - - -MEYEIOC_QBUF_CAPT - Queue a buffer for capture (the buffers must have been - obtained with a VIDIOCGMBUF call and mmap'ed by the - application). The argument to MEYEIOC_QBUF_CAPT is the - buffer number to queue (or -1 to end capture). The first - call to MEYEIOC_QBUF_CAPT starts the streaming capture. - -MEYEIOC_SYNC - Takes as an argument the buffer number you want to sync. - This ioctl blocks until the buffer is filled and ready - for the application to use. It returns the buffer size. - -MEYEIOC_STILLCAPT and MEYEIOC_STILLJCAPT - Takes a snapshot in an uncompressed or compressed jpeg format. - This ioctl blocks until the snapshot is done and returns (for - jpeg snapshot) the size of the image. The image data is - available from the first mmap'ed buffer. - -Look at the 'motioneye' application code for an actual example. diff --git a/Documentation/userspace-api/media/v4l/dev-subdev.rst b/Documentation/userspace-api/media/v4l/dev-subdev.rst index fd1de0a73a9f..a4f1df7093e8 100644 --- a/Documentation/userspace-api/media/v4l/dev-subdev.rst +++ b/Documentation/userspace-api/media/v4l/dev-subdev.rst @@ -29,6 +29,8 @@ will feature a character device node on which ioctls can be called to - negotiate image formats on individual pads +- inspect and modify internal data routing between pads of the same entity + Sub-device character device nodes, conventionally named ``/dev/v4l-subdev*``, use major number 81. @@ -404,6 +406,8 @@ pixel array is not rectangular but cross-shaped or round. The maximum size may also be smaller than the BOUNDS rectangle. +.. _format-propagation: + Order of configuration and format propagation --------------------------------------------- @@ -501,3 +505,165 @@ source pads. :maxdepth: 1 subdev-formats + +Streams, multiplexed media pads and internal routing +---------------------------------------------------- + +Simple V4L2 sub-devices do not support multiple, unrelated video streams, +and only a single stream can pass through a media link and a media pad. +Thus each pad contains a format and selection configuration for that +single stream. A subdev can do stream processing and split a stream into +two or compose two streams into one, but the inputs and outputs for the +subdev are still a single stream per pad. + +Some hardware, e.g. MIPI CSI-2, support multiplexed streams, that is, multiple +data streams are transmitted on the same bus, which is represented by a media +link connecting a transmitter source pad with a sink pad on the receiver. For +example, a camera sensor can produce two distinct streams, a pixel stream and a +metadata stream, which are transmitted on the multiplexed data bus, represented +by a media link which connects the single sensor's source pad with the receiver +sink pad. The stream-aware receiver will de-multiplex the streams received on +the its sink pad and allows to route them individually to one of its source +pads. + +Subdevice drivers that support multiplexed streams are compatible with +non-multiplexed subdev drivers, but, of course, require a routing configuration +where the link between those two types of drivers contains only a single +stream. + +Understanding streams +^^^^^^^^^^^^^^^^^^^^^ + +A stream is a stream of content (e.g. pixel data or metadata) flowing through +the media pipeline from a source (e.g. a sensor) towards the final sink (e.g. a +receiver and demultiplexer in a SoC). Each media link carries all the enabled +streams from one end of the link to the other, and sub-devices have routing +tables which describe how the incoming streams from sink pads are routed to the +source pads. + +A stream ID is a media pad-local identifier for a stream. Streams IDs of +the same stream must be equal on both ends of a link. In other words, +a particular stream ID must exist on both sides of a media +link, but another stream ID can be used for the same stream at the other side +of the sub-device. + +A stream at a specific point in the media pipeline is identified by the +sub-device and a (pad, stream) pair. For sub-devices that do not support +multiplexed streams the 'stream' field is always 0. + +Interaction between routes, streams, formats and selections +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The addition of streams to the V4L2 sub-device interface moves the sub-device +formats and selections from pads to (pad, stream) pairs. Besides the +usual pad, also the stream ID needs to be provided for setting formats and +selections. The order of configuring formats and selections along a stream is +the same as without streams (see :ref:`format-propagation`). + +Instead of the sub-device wide merging of streams from all sink pads +towards all source pads, data flows for each route are separate from each +other. Any number of routes from streams on sink pads towards streams on +source pads is allowed, to the extent supported by drivers. For every +stream on a source pad, however, only a single route is allowed. + +Any configurations of a stream within a pad, such as format or selections, +are independent of similar configurations on other streams. This is +subject to change in the future. + +Configuring streams +^^^^^^^^^^^^^^^^^^^ + +The configuration of the streams is done individually for each sub-device and +the validity of the streams between sub-devices is validated when the pipeline +is started. + +There are three steps in configuring the streams: + +1) Set up links. Connect the pads between sub-devices using the :ref:`Media +Controller API <media_controller>` + +2) Streams. Streams are declared and their routing is configured by +setting the routing table for the sub-device using +:ref:`VIDIOC_SUBDEV_S_ROUTING <VIDIOC_SUBDEV_G_ROUTING>` ioctl. Note that +setting the routing table will reset formats and selections in the +sub-device to default values. + +3) Configure formats and selections. Formats and selections of each stream +are configured separately as documented for plain sub-devices in +:ref:`format-propagation`. The stream ID is set to the same stream ID +associated with either sink or source pads of routes configured using the +:ref:`VIDIOC_SUBDEV_S_ROUTING <VIDIOC_SUBDEV_G_ROUTING>` ioctl. + +Multiplexed streams setup example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A simple example of a multiplexed stream setup might be as follows: + +- Two identical sensors (Sensor A and Sensor B). Each sensor has a single source + pad (pad 0) which carries a pixel data stream. + +- Multiplexer bridge (Bridge). The bridge has two sink pads, connected to the + sensors (pads 0, 1), and one source pad (pad 2), which outputs two streams. + +- Receiver in the SoC (Receiver). The receiver has a single sink pad (pad 0), + connected to the bridge, and two source pads (pads 1-2), going to the DMA + engine. The receiver demultiplexes the incoming streams to the source pads. + +- DMA Engines in the SoC (DMA Engine), one for each stream. Each DMA engine is + connected to a single source pad in the receiver. + +The sensors, the bridge and the receiver are modeled as V4L2 sub-devices, +exposed to userspace via /dev/v4l-subdevX device nodes. The DMA engines are +modeled as V4L2 devices, exposed to userspace via /dev/videoX nodes. + +To configure this pipeline, the userspace must take the following steps: + +1) Set up media links between entities: connect the sensors to the bridge, +bridge to the receiver, and the receiver to the DMA engines. This step does +not differ from normal non-multiplexed media controller setup. + +2) Configure routing + +.. flat-table:: Bridge routing table + :header-rows: 1 + + * - Sink Pad/Stream + - Source Pad/Stream + - Routing Flags + - Comments + * - 0/0 + - 2/0 + - V4L2_SUBDEV_ROUTE_FL_ACTIVE + - Pixel data stream from Sensor A + * - 1/0 + - 2/1 + - V4L2_SUBDEV_ROUTE_FL_ACTIVE + - Pixel data stream from Sensor B + +.. flat-table:: Receiver routing table + :header-rows: 1 + + * - Sink Pad/Stream + - Source Pad/Stream + - Routing Flags + - Comments + * - 0/0 + - 1/0 + - V4L2_SUBDEV_ROUTE_FL_ACTIVE + - Pixel data stream from Sensor A + * - 0/1 + - 2/0 + - V4L2_SUBDEV_ROUTE_FL_ACTIVE + - Pixel data stream from Sensor B + +3) Configure formats and selections + +After configuring routing, the next step is configuring the formats and +selections for the streams. This is similar to performing this step without +streams, with just one exception: the ``stream`` field needs to be assigned +to the value of the stream ID. + +A common way to accomplish this is to start from the sensors and propagate the +configurations along the stream towards the receiver, +using :ref:`VIDIOC_SUBDEV_S_FMT <VIDIOC_SUBDEV_G_FMT>` ioctls to configure each +stream endpoint in each sub-device. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst index 73cd99828010..58f6ae25b2e7 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst @@ -271,7 +271,7 @@ please make a proposal on the linux-media mailing list. The implementation is based on AST2600 A3 datasheet, revision 0.9, which is not publicly available. Or you can reference Video stream data format – ASPEED mode compression of SDK_User_Guide which available on - AspeedTech-BMC/openbmc/releases. + `github <https://github.com/AspeedTech-BMC/openbmc/releases/>`__. Decoder's implementation can be found here, `aspeed_codec <https://github.com/AspeedTech-BMC/aspeed_codec/>`__ diff --git a/Documentation/userspace-api/media/v4l/user-func.rst b/Documentation/userspace-api/media/v4l/user-func.rst index 53e604bd7d60..228c1521f190 100644 --- a/Documentation/userspace-api/media/v4l/user-func.rst +++ b/Documentation/userspace-api/media/v4l/user-func.rst @@ -70,6 +70,7 @@ Function Reference vidioc-subdev-g-crop vidioc-subdev-g-fmt vidioc-subdev-g-frame-interval + vidioc-subdev-g-routing vidioc-subdev-g-selection vidioc-subdev-querycap vidioc-subscribe-event diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst index 3703943b412f..8def4c05d3da 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst @@ -92,7 +92,10 @@ multiple pads of the same sub-device is not defined. - Frame intervals to be enumerated, from enum :ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`. * - __u32 - - ``reserved``\ [8] + - ``stream`` + - Stream identifier. + * - __u32 + - ``reserved``\ [7] - Reserved for future extensions. Applications and drivers must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst index c25a9896df0e..3ef361c0dca7 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst @@ -97,7 +97,10 @@ information about try formats. - Frame sizes to be enumerated, from enum :ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`. * - __u32 - - ``reserved``\ [8] + - ``stream`` + - Stream identifier. + * - __u32 + - ``reserved``\ [7] - Reserved for future extensions. Applications and drivers must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst index 417f1a19bcc4..248f6f9ee7c5 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst @@ -73,7 +73,10 @@ information about the try formats. - ``flags`` - See :ref:`v4l2-subdev-mbus-code-flags` * - __u32 - - ``reserved``\ [7] + - ``stream`` + - Stream identifier. + * - __u32 + - ``reserved``\ [6] - Reserved for future extensions. Applications and drivers must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst index bd15c0a5a66b..1d267f7e7991 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst @@ -96,7 +96,10 @@ modified format should be as close as possible to the original request. - ``rect`` - Crop rectangle boundaries, in pixels. * - __u32 - - ``reserved``\ [8] + - ``stream`` + - Stream identifier. + * - __u32 + - ``reserved``\ [7] - Reserved for future extensions. Applications and drivers must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst index 7acdbb939d89..ed253a1e44b7 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst @@ -102,7 +102,10 @@ should be as close as possible to the original request. - Definition of an image format, see :c:type:`v4l2_mbus_framefmt` for details. * - __u32 - - ``reserved``\ [8] + - ``stream`` + - Stream identifier. + * - __u32 + - ``reserved``\ [7] - Reserved for future extensions. Applications and drivers must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst index d7fe7543c506..842f962d2aea 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst @@ -90,7 +90,10 @@ the same sub-device is not defined. - ``interval`` - Period, in seconds, between consecutive video frames. * - __u32 - - ``reserved``\ [9] + - ``stream`` + - Stream identifier. + * - __u32 + - ``reserved``\ [8] - Reserved for future extensions. Applications and drivers must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst new file mode 100644 index 000000000000..68ca343c3b44 --- /dev/null +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst @@ -0,0 +1,147 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: V4L + +.. _VIDIOC_SUBDEV_G_ROUTING: + +****************************************************** +ioctl VIDIOC_SUBDEV_G_ROUTING, VIDIOC_SUBDEV_S_ROUTING +****************************************************** + +Name +==== + +VIDIOC_SUBDEV_G_ROUTING - VIDIOC_SUBDEV_S_ROUTING - Get or set routing between streams of media pads in a media entity. + + +Synopsis +======== + +.. c:macro:: VIDIOC_SUBDEV_G_ROUTING + +``int ioctl(int fd, VIDIOC_SUBDEV_G_ROUTING, struct v4l2_subdev_routing *argp)`` + +.. c:macro:: VIDIOC_SUBDEV_S_ROUTING + +``int ioctl(int fd, VIDIOC_SUBDEV_S_ROUTING, struct v4l2_subdev_routing *argp)`` + +Arguments +========= + +``fd`` + File descriptor returned by :ref:`open() <func-open>`. + +``argp`` + Pointer to struct :c:type:`v4l2_subdev_routing`. + + +Description +=========== + +These ioctls are used to get and set the routing in a media entity. +The routing configuration determines the flows of data inside an entity. + +Drivers report their current routing tables using the +``VIDIOC_SUBDEV_G_ROUTING`` ioctl and application may enable or disable routes +with the ``VIDIOC_SUBDEV_S_ROUTING`` ioctl, by adding or removing routes and +setting or clearing flags of the ``flags`` field of a +struct :c:type:`v4l2_subdev_route`. + +All stream configurations are reset when ``VIDIOC_SUBDEV_S_ROUTING`` is called. This +means that the userspace must reconfigure all streams after calling the ioctl +with e.g. ``VIDIOC_SUBDEV_S_FMT``. + +Only subdevices which have both sink and source pads can support routing. + +When inspecting routes through ``VIDIOC_SUBDEV_G_ROUTING`` and the application +provided ``num_routes`` is not big enough to contain all the available routes +the subdevice exposes, drivers return the ENOSPC error code and adjust the +value of the ``num_routes`` field. Application should then reserve enough memory +for all the route entries and call ``VIDIOC_SUBDEV_G_ROUTING`` again. + +.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| + +.. c:type:: v4l2_subdev_routing + +.. flat-table:: struct v4l2_subdev_routing + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u32 + - ``which`` + - Format to modified, from enum + :ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`. + * - struct :c:type:`v4l2_subdev_route` + - ``routes[]`` + - Array of struct :c:type:`v4l2_subdev_route` entries + * - __u32 + - ``num_routes`` + - Number of entries of the routes array + * - __u32 + - ``reserved``\ [5] + - Reserved for future extensions. Applications and drivers must set + the array to zero. + +.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| + +.. c:type:: v4l2_subdev_route + +.. flat-table:: struct v4l2_subdev_route + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u32 + - ``sink_pad`` + - Sink pad number. + * - __u32 + - ``sink_stream`` + - Sink pad stream number. + * - __u32 + - ``source_pad`` + - Source pad number. + * - __u32 + - ``source_stream`` + - Source pad stream number. + * - __u32 + - ``flags`` + - Route enable/disable flags + :ref:`v4l2_subdev_routing_flags <v4l2-subdev-routing-flags>`. + * - __u32 + - ``reserved``\ [5] + - Reserved for future extensions. Applications and drivers must set + the array to zero. + +.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| + +.. _v4l2-subdev-routing-flags: + +.. flat-table:: enum v4l2_subdev_routing_flags + :header-rows: 0 + :stub-columns: 0 + :widths: 3 1 4 + + * - V4L2_SUBDEV_ROUTE_FL_ACTIVE + - 0 + - The route is enabled. Set by applications. + +Return Value +============ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. + +ENOSPC + The application provided ``num_routes`` is not big enough to contain + all the available routes the subdevice exposes. + +EINVAL + The sink or source pad identifiers reference a non-existing pad, or reference + pads of different types (ie. the sink_pad identifiers refers to a source pad) + or the sink or source stream identifiers reference a non-existing stream on + the sink or source pad. + +E2BIG + The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is + larger than the number of routes the driver can handle. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst index f9172a42f036..6b629c19168c 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst @@ -94,7 +94,10 @@ Selection targets and flags are documented in - ``r`` - Selection rectangle, in pixels. * - __u32 - - ``reserved``\ [8] + - ``stream`` + - Stream identifier. + * - __u32 + - ``reserved``\ [7] - Reserved for future extensions. Applications and drivers must set the array to zero. diff --git a/MAINTAINERS b/MAINTAINERS index eb223dcf0f62..a86c34469e10 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2739,7 +2739,7 @@ M: Marek Szyprowski <m.szyprowski@samsung.com> L: linux-samsung-soc@vger.kernel.org L: linux-media@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/media/s5p-cec.txt +F: Documentation/devicetree/bindings/media/cec/samsung,s5p-cec.yaml F: drivers/media/cec/platform/s5p/ ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT @@ -2873,7 +2873,7 @@ M: Hans Verkuil <hverkuil-cisco@xs4all.nl> L: linux-tegra@vger.kernel.org L: linux-media@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/media/tegra-cec.txt +F: Documentation/devicetree/bindings/media/cec/nvidia,tegra114-cec.yaml F: drivers/media/cec/platform/tegra/ ARM/TESLA FSD SoC SUPPORT @@ -3073,7 +3073,7 @@ M: Tianshu Qiu <tian.shu.qiu@intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/i2c/ak7375.txt +F: Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml F: drivers/media/i2c/ak7375.c ASAHI KASEI AK8974 DRIVER @@ -4699,7 +4699,7 @@ S: Supported W: http://linuxtv.org T: git git://linuxtv.org/media_tree.git F: Documentation/ABI/testing/debugfs-cec-error-inj -F: Documentation/devicetree/bindings/media/cec.txt +F: Documentation/devicetree/bindings/media/cec/cec-common.yaml F: Documentation/driver-api/media/cec-core.rst F: Documentation/userspace-api/media/cec F: drivers/media/cec/ @@ -4715,7 +4715,7 @@ L: linux-media@vger.kernel.org S: Supported W: http://linuxtv.org T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/cec-gpio.txt +F: Documentation/devicetree/bindings/media/cec/cec-gpio.yaml F: drivers/media/cec/platform/cec-gpio/ CELL BROADBAND ENGINE ARCHITECTURE @@ -13004,7 +13004,6 @@ F: include/media/ F: include/uapi/linux/dvb/ F: include/uapi/linux/ivtv* F: include/uapi/linux/media.h -F: include/uapi/linux/meye.h F: include/uapi/linux/uvcvideo.h F: include/uapi/linux/v4l2-* F: include/uapi/linux/videodev2.h @@ -13500,7 +13499,7 @@ L: linux-amlogic@lists.infradead.org S: Supported W: http://linux-meson.com/ T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml +F: Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml F: drivers/media/cec/platform/meson/ao-cec-g12a.c F: drivers/media/cec/platform/meson/ao-cec.c @@ -14116,13 +14115,6 @@ F: drivers/most/ F: drivers/staging/most/ F: include/linux/most.h -MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER -S: Orphan -W: http://popies.net/meye/ -F: Documentation/userspace-api/media/drivers/meye* -F: drivers/staging/media/deprecated/meye/ -F: include/uapi/linux/meye.h - MOTORCOMM PHY DRIVER M: Peter Geis <pgwipeout@gmail.com> M: Frank <Frank.Sae@motor-comm.com> @@ -15442,6 +15434,7 @@ M: Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml F: drivers/media/i2c/ov5670.c OMNIVISION OV5675 SENSOR DRIVER @@ -15449,6 +15442,7 @@ M: Shawn Tu <shawnx.tu@intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml F: drivers/media/i2c/ov5675.c OMNIVISION OV5693 SENSOR DRIVER @@ -15498,6 +15492,15 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml F: drivers/media/i2c/ov8856.c +OMNIVISION OV8858 SENSOR DRIVER +M: Jacopo Mondi <jacopo.mondi@ideasonboard.com> +M: Nicholas Roth <nicholas@rothemail.net> +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml +F: drivers/media/i2c/ov8858.c + OMNIVISION OV9282 SENSOR DRIVER M: Paul J. Murphy <paul.j.murphy@intel.com> M: Daniele Alessandrelli <daniele.alessandrelli@intel.com> @@ -18405,7 +18408,9 @@ M: Hans Verkuil <hverkuil@xs4all.nl> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: drivers/staging/media/deprecated/saa7146/ +F: drivers/media/common/saa7146/ +F: drivers/media/pci/saa7146/ +F: include/media/drv-intf/saa7146* SAFESETID SECURITY MODULE M: Micah Morton <mortonm@chromium.org> @@ -19464,6 +19469,15 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml F: drivers/media/i2c/imx290.c +SONY IMX296 SENSOR DRIVER +M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml +F: drivers/media/i2c/imx296.c + SONY IMX319 SENSOR DRIVER M: Bingbu Cao <bingbu.cao@intel.com> L: linux-media@vger.kernel.org @@ -19505,6 +19519,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml F: drivers/media/i2c/imx412.c +SONY IMX415 SENSOR DRIVER +M: Michael Riesch <michael.riesch@wolfvision.net> +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml +F: drivers/media/i2c/imx415.c + SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky <maximlevitsky@gmail.com> M: Alex Dubov <oakad@yahoo.com> @@ -19951,7 +19973,7 @@ F: sound/soc/sti/ STI CEC DRIVER M: Alain Volmat <alain.volmat@foss.st.com> S: Maintained -F: Documentation/devicetree/bindings/media/stih-cec.txt +F: Documentation/devicetree/bindings/media/cec/st,stih-cec.yaml F: drivers/media/cec/platform/sti/ STK1160 USB VIDEO CAPTURE DRIVER @@ -21027,15 +21049,6 @@ W: http://sourceforge.net/projects/tlan/ F: Documentation/networking/device_drivers/ethernet/ti/tlan.rst F: drivers/net/ethernet/ti/tlan.* -TM6000 VIDEO4LINUX DRIVER -M: Mauro Carvalho Chehab <mchehab@kernel.org> -L: linux-media@vger.kernel.org -S: Odd fixes -W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git -F: Documentation/admin-guide/media/tm6000* -F: drivers/staging/media/deprecated/tm6000/ - TMIO/SDHI MMC DRIVER M: Wolfram Sang <wsa+renesas@sang-engineering.com> L: linux-mmc@vger.kernel.org @@ -21785,16 +21798,6 @@ S: Orphan W: http://linux-lc100020.sourceforge.net F: drivers/net/wireless/zydas/zd1201.* -USB ZR364XX DRIVER -M: Antoine Jacquet <royale@zerezo.com> -L: linux-usb@vger.kernel.org -L: linux-media@vger.kernel.org -S: Maintained -W: http://royale.zerezo.com/zr364xx/ -T: git git://linuxtv.org/media_tree.git -F: Documentation/admin-guide/media/zr364xx* -F: drivers/staging/media/deprecated/zr364xx/ - USER DATAGRAM PROTOCOL (UDP) M: Willem de Bruijn <willemdebruijn.kernel@gmail.com> S: Maintained diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index b1bc58da27fc..adcb6655385a 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -25,6 +25,7 @@ config VIDEO_TVEEPROM depends on I2C source "drivers/media/common/b2c2/Kconfig" +source "drivers/media/common/saa7146/Kconfig" source "drivers/media/common/siano/Kconfig" source "drivers/media/common/v4l2-tpg/Kconfig" source "drivers/media/common/videobuf2/Kconfig" diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 3f17d696feb2..c5ab905e7c20 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += b2c2/ siano/ v4l2-tpg/ videobuf2/ +obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/ # Please keep it alphabetically sorted by Kconfig name # (e. g. LC_ALL=C sort Makefile) diff --git a/drivers/staging/media/deprecated/saa7146/common/Kconfig b/drivers/media/common/saa7146/Kconfig index a0aa155e5d85..a0aa155e5d85 100644 --- a/drivers/staging/media/deprecated/saa7146/common/Kconfig +++ b/drivers/media/common/saa7146/Kconfig diff --git a/drivers/staging/media/deprecated/saa7146/common/Makefile b/drivers/media/common/saa7146/Makefile index 2a6337feaec8..2a6337feaec8 100644 --- a/drivers/staging/media/deprecated/saa7146/common/Makefile +++ b/drivers/media/common/saa7146/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c index da21d346b870..e50fa0ff7c5d 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c +++ b/drivers/media/common/saa7146/saa7146_core.c @@ -8,8 +8,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <media/drv-intf/saa7146.h> #include <linux/module.h> -#include "saa7146.h" static int saa7146_num; diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index aa14698a9c54..e9a15de6126e 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> -#include "saa7146_vv.h" /****************************************************************************/ /* resource management functions, shamelessly stolen from saa7134 driver */ diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c index b1222a4cfa4a..6c9946a402ee 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146/saa7146_hlp.c @@ -3,7 +3,7 @@ #include <linux/kernel.h> #include <linux/export.h> -#include "saa7146_vv.h" +#include <media/drv-intf/saa7146_vv.h> static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) { diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c index 7a33fe51775a..df9ebe2a168c 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146/saa7146_i2c.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "saa7146_vv.h" +#include <media/drv-intf/saa7146_vv.h> static u32 saa7146_i2c_func(struct i2c_adapter *adapter) { diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index 2d4a05d7bc5b..bd442b984423 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -#include "saa7146_vv.h" +#include <media/drv-intf/saa7146_vv.h> static int vbi_pixel_to_capture = 720 * 2; diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 4598a44231fa..2296765079a4 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -1,10 +1,10 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <media/drv-intf/saa7146_vv.h> #include <media/v4l2-event.h> #include <media/v4l2-ctrls.h> #include <linux/module.h> #include <linux/kernel.h> -#include "saa7146_vv.h" static int max_memory = 32; diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 53e495223ea0..cf6727d9c81f 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -502,27 +502,11 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) * related information, if no buffers are left return the queue to an * uninitialized state. Might be called even if the queue has already been freed. */ -static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) +static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) { unsigned int buffer; - /* - * Sanity check: when preparing a buffer the queue lock is released for - * a short while (see __buf_prepare for the details), which would allow - * a race with a reqbufs which can call this function. Removing the - * buffers from underneath __buf_prepare is obviously a bad idea, so we - * check if any of the buffers is in the state PREPARING, and if so we - * just return -EAGAIN. - */ - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; - ++buffer) { - if (q->bufs[buffer] == NULL) - continue; - if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) { - dprintk(q, 1, "preparing buffers, cannot free\n"); - return -EAGAIN; - } - } + lockdep_assert_held(&q->mmap_lock); /* Call driver-provided cleanup function for each buffer, if provided */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; @@ -616,7 +600,6 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) q->memory = VB2_MEMORY_UNKNOWN; INIT_LIST_HEAD(&q->queued_list); } - return 0; } bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) @@ -798,10 +781,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * queued without ever calling STREAMON. */ __vb2_queue_cancel(q); - ret = __vb2_queue_free(q, q->num_buffers); + __vb2_queue_free(q, q->num_buffers); mutex_unlock(&q->mmap_lock); - if (ret) - return ret; /* * In case of REQBUFS(0) return immediately without calling diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c index 4cf2d7cfd3f5..0a1f3899d72c 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c @@ -2162,11 +2162,11 @@ int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd else *task_completed = 0; - return ret; + return 0; } if (cpu_status != 0) { *task_completed = 0; - return ret; + return 0; } ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status); diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c index fe3c6f8b1b3e..c7e79da8c432 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c @@ -833,12 +833,12 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (sync_stat == 6) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } ret = @@ -854,7 +854,7 @@ int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd @@ -893,15 +893,15 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (ts_lock) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } else if (!unlock_detected) { *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } ret = @@ -915,5 +915,5 @@ int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c index dd32004a12d8..a9ab983348c8 100644 --- a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c @@ -1024,12 +1024,12 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (sync_stat == 6) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } ret = @@ -1045,7 +1045,7 @@ int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd @@ -1084,15 +1084,15 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } if (ts_lock) { *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED; - return ret; + return 0; } else if (!unlock_detected) { *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } ret = @@ -1106,7 +1106,7 @@ int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd else *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; - return ret; + return 0; } int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 1dff59ca21a1..6bf6559b127f 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -9539,7 +9539,8 @@ ctrl_get_qam_sig_quality(struct drx_demod_instance *demod) qam_sl_sig_power = DRXJ_QAM_SL_SIG_POWER_QAM256 << 2; break; default: - return -EIO; + rc = -EIO; + goto rw_error; } /* ------------------------------ */ @@ -10916,7 +10917,8 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard) break; case DRX_STANDARD_AUTO: default: - return -EINVAL; + rc = -EINVAL; + goto rw_error; } /* @@ -11463,7 +11465,8 @@ static int drxj_open(struct drx_demod_instance *demod) if (DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode)) { pr_err("Should powerup before loading the firmware."); - return -EINVAL; + rc = -EINVAL; + goto rw_error; } rc = drx_ctrl_u_code(demod, &ucode_info, UCODE_UPLOAD); diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index baf2a378e565..e35e00db7dbb 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -870,8 +870,9 @@ EXPORT_SYMBOL(dvb_pll_attach); static int -dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) +dvb_pll_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct dvb_pll_config *cfg; struct dvb_frontend *fe; unsigned int desc_id; @@ -941,7 +942,7 @@ static struct i2c_driver dvb_pll_driver = { .driver = { .name = "dvb_pll", }, - .probe = dvb_pll_probe, + .probe_new = dvb_pll_probe, .remove = dvb_pll_remove, .id_table = dvb_pll_id, }; diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 4e844b2ef597..f26508b217ee 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1760,9 +1760,9 @@ static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client) return dev->muxc->adapter[0]; } -static int m88ds3103_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int m88ds3103_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct m88ds3103_dev *dev; struct m88ds3103_platform_data *pdata = client->dev.platform_data; int ret; @@ -1941,7 +1941,7 @@ static struct i2c_driver m88ds3103_driver = { .name = "m88ds3103", .suppress_bind_attrs = true, }, - .probe = m88ds3103_probe, + .probe_new = m88ds3103_probe, .remove = m88ds3103_remove, .id_table = m88ds3103_id_table, }; diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 2505f1e5794e..d3e29937cf4c 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -1498,6 +1498,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { struct mb86a16_state *state = fe->demodulator_priv; + int ret = -EREMOTEIO; int i; u8 regs; @@ -1510,8 +1511,10 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, regs = 0x18; - if (cmd->msg_len > 5 || cmd->msg_len < 4) - return -EINVAL; + if (cmd->msg_len > 5 || cmd->msg_len < 4) { + ret = -EINVAL; + goto err; + } for (i = 0; i < cmd->msg_len; i++) { if (mb86a16_write(state, regs, cmd->msg[i]) < 0) @@ -1532,7 +1535,7 @@ static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, err: dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); - return -EREMOTEIO; + return ret; } static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index 452571b380b7..1f1753f2ab1a 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -673,9 +673,9 @@ static const struct regmap_config regmap_config = { .cache_type = REGCACHE_NONE, }; -static int mn88443x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mn88443x_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct mn88443x_config *conf = client->dev.platform_data; struct mn88443x_priv *chip; struct device *dev = &client->dev; @@ -800,7 +800,7 @@ static struct i2c_driver mn88443x_driver = { .name = "mn88443x", .of_match_table = of_match_ptr(mn88443x_of_match), }, - .probe = mn88443x_probe, + .probe_new = mn88443x_probe, .remove = mn88443x_remove, .id_table = mn88443x_i2c_id, }; diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index c22d2a2b2a45..77a991bf4713 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -779,9 +779,9 @@ static const struct dvb_frontend_ops tc90522_ops_ter = { }; -static int tc90522_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tc90522_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct tc90522_state *state; struct tc90522_config *cfg; const struct dvb_frontend_ops *ops; @@ -840,7 +840,7 @@ static struct i2c_driver tc90522_driver = { .driver = { .name = "tc90522", }, - .probe = tc90522_probe, + .probe_new = tc90522_probe, .remove = tc90522_remove, .id_table = tc90522_id, }; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 833241897d63..c3d5952ca27e 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -162,6 +162,19 @@ config VIDEO_IMX290 To compile this driver as a module, choose M here: the module will be called imx290. +config VIDEO_IMX296 + tristate "Sony IMX296 sensor support" + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the Sony + IMX296 camera. + + To compile this driver as a module, choose M here: the + module will be called imx296. + config VIDEO_IMX319 tristate "Sony IMX319 sensor support" depends on I2C && VIDEO_DEV @@ -228,6 +241,20 @@ config VIDEO_IMX412 To compile this driver as a module, choose M here: the module will be called imx412. +config VIDEO_IMX415 + tristate "Sony IMX415 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_DEV + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX415 camera. + + To compile this driver as a module, choose M here: the + module will be called imx415. + config VIDEO_MAX9271_LIB tristate @@ -645,6 +672,19 @@ config VIDEO_OV8856 To compile this driver as a module, choose M here: the module will be called ov8856. +config VIDEO_OV8858 + tristate "OmniVision OV8858 sensor support" + depends on I2C && PM && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for OmniVision + OV8858 camera sensor. + + To compile this driver as a module, choose M here: the + module will be called ov8858. + config VIDEO_OV8865 tristate "OmniVision OV8865 sensor support" depends on I2C && PM && VIDEO_DEV diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 4d6c052bb5a7..4f5e9d9cee85 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -43,11 +43,13 @@ obj-$(CONFIG_VIDEO_IMX219) += imx219.o obj-$(CONFIG_VIDEO_IMX258) += imx258.o obj-$(CONFIG_VIDEO_IMX274) += imx274.o obj-$(CONFIG_VIDEO_IMX290) += imx290.o +obj-$(CONFIG_VIDEO_IMX296) += imx296.o obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX334) += imx334.o obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o +obj-$(CONFIG_VIDEO_IMX415) += imx415.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o @@ -96,6 +98,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV8856) += ov8856.o +obj-$(CONFIG_VIDEO_OV8858) += ov8858.o obj-$(CONFIG_VIDEO_OV8865) += ov8865.o obj-$(CONFIG_VIDEO_OV9282) += ov9282.o obj-$(CONFIG_VIDEO_OV9640) += ov9640.o diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 216fe396973f..a22402b7acff 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1393,9 +1393,9 @@ out_unlock: return ret; } -static int adv7180_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adv7180_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device_node *np = client->dev.of_node; struct adv7180_state *state; struct v4l2_subdev *sd; @@ -1610,7 +1610,7 @@ static struct i2c_driver adv7180_driver = { .pm = ADV7180_PM_OPS, .of_match_table = of_match_ptr(adv7180_of_id), }, - .probe = adv7180_probe, + .probe_new = adv7180_probe, .remove = adv7180_remove, .id_table = adv7180_id, }; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index bda0c547ce44..9d218962d7c8 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -3401,9 +3401,9 @@ static void adv76xx_reset(struct adv76xx_state *state) } } -static int adv76xx_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adv76xx_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); static const struct v4l2_dv_timings cea640x480 = V4L2_DV_BT_CEA_640X480P59_94; struct adv76xx_state *state; @@ -3686,7 +3686,7 @@ static struct i2c_driver adv76xx_driver = { .name = "adv7604", .of_match_table = of_match_ptr(adv76xx_of_id), }, - .probe = adv76xx_probe, + .probe_new = adv76xx_probe, .remove = adv76xx_remove, .id_table = adv76xx_i2c_id, }; diff --git a/drivers/media/i2c/ak7375.c b/drivers/media/i2c/ak7375.c index 1af9f698eecf..e7cec45bc271 100644 --- a/drivers/media/i2c/ak7375.c +++ b/drivers/media/i2c/ak7375.c @@ -6,6 +6,7 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -23,17 +24,29 @@ */ #define AK7375_CTRL_STEPS 64 #define AK7375_CTRL_DELAY_US 1000 +/* + * The vcm may take up 10 ms (tDELAY) to power on and start taking + * I2C messages. Based on AK7371 datasheet. + */ +#define AK7375_POWER_DELAY_US 10000 #define AK7375_REG_POSITION 0x0 #define AK7375_REG_CONT 0x2 #define AK7375_MODE_ACTIVE 0x0 #define AK7375_MODE_STANDBY 0x40 +static const char * const ak7375_supply_names[] = { + "vdd", + "vio", +}; + /* ak7375 device structure */ struct ak7375_device { struct v4l2_ctrl_handler ctrls_vcm; struct v4l2_subdev sd; struct v4l2_ctrl *focus; + struct regulator_bulk_data supplies[ARRAY_SIZE(ak7375_supply_names)]; + /* active or standby mode */ bool active; }; @@ -133,12 +146,24 @@ static int ak7375_probe(struct i2c_client *client) { struct ak7375_device *ak7375_dev; int ret; + unsigned int i; ak7375_dev = devm_kzalloc(&client->dev, sizeof(*ak7375_dev), GFP_KERNEL); if (!ak7375_dev) return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(ak7375_supply_names); i++) + ak7375_dev->supplies[i].supply = ak7375_supply_names[i]; + + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(ak7375_supply_names), + ak7375_dev->supplies); + if (ret) { + dev_err_probe(&client->dev, ret, "Failed to get regulators\n"); + return ret; + } + v4l2_i2c_subdev_init(&ak7375_dev->sd, client, &ak7375_ops); ak7375_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ak7375_dev->sd.internal_ops = &ak7375_int_ops; @@ -208,6 +233,11 @@ static int __maybe_unused ak7375_vcm_suspend(struct device *dev) if (ret) dev_err(dev, "%s I2C failure: %d\n", __func__, ret); + ret = regulator_bulk_disable(ARRAY_SIZE(ak7375_supply_names), + ak7375_dev->supplies); + if (ret) + return ret; + ak7375_dev->active = false; return 0; @@ -228,6 +258,14 @@ static int __maybe_unused ak7375_vcm_resume(struct device *dev) if (ak7375_dev->active) return 0; + ret = regulator_bulk_enable(ARRAY_SIZE(ak7375_supply_names), + ak7375_dev->supplies); + if (ret) + return ret; + + /* Wait for vcm to become ready */ + usleep_range(AK7375_POWER_DELAY_US, AK7375_POWER_DELAY_US + 500); + ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_CONT, AK7375_MODE_ACTIVE, 1); if (ret) { diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c index 9461589aea30..670f89de32d4 100644 --- a/drivers/media/i2c/cs53l32a.c +++ b/drivers/media/i2c/cs53l32a.c @@ -128,9 +128,9 @@ static const struct v4l2_subdev_ops cs53l32a_ops = { * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int cs53l32a_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cs53l32a_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct cs53l32a_state *state; struct v4l2_subdev *sd; int i; @@ -209,7 +209,7 @@ static struct i2c_driver cs53l32a_driver = { .driver = { .name = "cs53l32a", }, - .probe = cs53l32a_probe, + .probe_new = cs53l32a_probe, .remove = cs53l32a_remove, .id_table = cs53l32a_id, }; diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 77bd79a5954e..f9471c9e3a74 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -42,10 +42,16 @@ /* External clock frequency is 24.0M */ #define IMX219_XCLK_FREQ 24000000 -/* Pixel rate is fixed at 182.4M for all the modes */ +/* Pixel rate is fixed for all the modes */ #define IMX219_PIXEL_RATE 182400000 +#define IMX219_PIXEL_RATE_4LANE 280800000 #define IMX219_DEFAULT_LINK_FREQ 456000000 +#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000 + +#define IMX219_REG_CSI_LANE_MODE 0x0114 +#define IMX219_CSI_2_LANE_MODE 0x01 +#define IMX219_CSI_4_LANE_MODE 0x03 /* V_TIMING internal */ #define IMX219_REG_VTS 0x0160 @@ -89,6 +95,12 @@ #define IMX219_REG_ORIENTATION 0x0172 +/* Binning Mode */ +#define IMX219_REG_BINNING_MODE 0x0174 +#define IMX219_BINNING_NONE 0x0000 +#define IMX219_BINNING_2X2 0x0101 +#define IMX219_BINNING_2X2_ANALOG 0x0303 + /* Test Pattern Control */ #define IMX219_REG_TEST_PATTERN 0x0600 #define IMX219_TEST_PATTERN_DISABLE 0 @@ -143,25 +155,66 @@ struct imx219_mode { /* Default register values */ struct imx219_reg_list reg_list; + + /* 2x2 binning is used */ + bool binning; }; -/* - * Register sets lifted off the i2C interface from the Raspberry Pi firmware - * driver. - * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. - */ -static const struct imx219_reg mode_3280x2464_regs[] = { - {0x0100, 0x00}, +static const struct imx219_reg imx219_common_regs[] = { + {0x0100, 0x00}, /* Mode Select */ + + /* To Access Addresses 3000-5fff, send the following commands */ {0x30eb, 0x0c}, {0x30eb, 0x05}, {0x300a, 0xff}, {0x300b, 0xff}, {0x30eb, 0x05}, {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, + + /* PLL Clock Table */ + {0x0301, 0x05}, /* VTPXCK_DIV */ + {0x0303, 0x01}, /* VTSYSCK_DIV */ + {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ + {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ + {0x0306, 0x00}, /* PLL_VT_MPY */ + {0x0307, 0x39}, + {0x030b, 0x01}, /* OP_SYS_CLK_DIV */ + {0x030c, 0x00}, /* PLL_OP_MPY */ + {0x030d, 0x72}, + + /* Undocumented registers */ + {0x455e, 0x00}, + {0x471e, 0x4b}, + {0x4767, 0x0f}, + {0x4750, 0x14}, + {0x4540, 0x00}, + {0x47b4, 0x14}, + {0x4713, 0x30}, + {0x478b, 0x10}, + {0x478f, 0x10}, + {0x4793, 0x10}, + {0x4797, 0x0e}, + {0x479b, 0x0e}, + + /* Frame Bank Register Group "A" */ + {0x0162, 0x0d}, /* Line_Length_A */ + {0x0163, 0x78}, + {0x0170, 0x01}, /* X_ODD_INC_A */ + {0x0171, 0x01}, /* Y_ODD_INC_A */ + + /* Output setup registers */ + {0x0114, 0x01}, /* CSI 2-Lane Mode */ + {0x0128, 0x00}, /* DPHY Auto Mode */ + {0x012a, 0x18}, /* EXCK_Freq */ {0x012b, 0x00}, +}; + +/* + * Register sets lifted off the i2C interface from the Raspberry Pi firmware + * driver. + * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. + */ +static const struct imx219_reg mode_3280x2464_regs[] = { {0x0164, 0x00}, {0x0165, 0x00}, {0x0166, 0x0c}, @@ -174,53 +227,13 @@ static const struct imx219_reg mode_3280x2464_regs[] = { {0x016d, 0xd0}, {0x016e, 0x09}, {0x016f, 0xa0}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x00}, - {0x0175, 0x00}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x0c}, {0x0625, 0xd0}, {0x0626, 0x09}, {0x0627, 0xa0}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, - {0x0162, 0x0d}, - {0x0163, 0x78}, }; static const struct imx219_reg mode_1920_1080_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x05}, - {0x30eb, 0x0c}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, - {0x012b, 0x00}, - {0x0162, 0x0d}, - {0x0163, 0x78}, {0x0164, 0x02}, {0x0165, 0xa8}, {0x0166, 0x0a}, @@ -233,49 +246,13 @@ static const struct imx219_reg mode_1920_1080_regs[] = { {0x016d, 0x80}, {0x016e, 0x04}, {0x016f, 0x38}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x00}, - {0x0175, 0x00}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x07}, {0x0625, 0x80}, {0x0626, 0x04}, {0x0627, 0x38}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, }; static const struct imx219_reg mode_1640_1232_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x0c}, - {0x30eb, 0x05}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, - {0x012b, 0x00}, {0x0164, 0x00}, {0x0165, 0x00}, {0x0166, 0x0c}, @@ -288,53 +265,13 @@ static const struct imx219_reg mode_1640_1232_regs[] = { {0x016d, 0x68}, {0x016e, 0x04}, {0x016f, 0xd0}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x01}, - {0x0175, 0x01}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, {0x0627, 0xd0}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, - {0x0162, 0x0d}, - {0x0163, 0x78}, }; static const struct imx219_reg mode_640_480_regs[] = { - {0x0100, 0x00}, - {0x30eb, 0x05}, - {0x30eb, 0x0c}, - {0x300a, 0xff}, - {0x300b, 0xff}, - {0x30eb, 0x05}, - {0x30eb, 0x09}, - {0x0114, 0x01}, - {0x0128, 0x00}, - {0x012a, 0x18}, - {0x012b, 0x00}, - {0x0162, 0x0d}, - {0x0163, 0x78}, {0x0164, 0x03}, {0x0165, 0xe8}, {0x0166, 0x08}, @@ -347,35 +284,10 @@ static const struct imx219_reg mode_640_480_regs[] = { {0x016d, 0x80}, {0x016e, 0x01}, {0x016f, 0xe0}, - {0x0170, 0x01}, - {0x0171, 0x01}, - {0x0174, 0x03}, - {0x0175, 0x03}, - {0x0301, 0x05}, - {0x0303, 0x01}, - {0x0304, 0x03}, - {0x0305, 0x03}, - {0x0306, 0x00}, - {0x0307, 0x39}, - {0x030b, 0x01}, - {0x030c, 0x00}, - {0x030d, 0x72}, {0x0624, 0x06}, {0x0625, 0x68}, {0x0626, 0x04}, {0x0627, 0xd0}, - {0x455e, 0x00}, - {0x471e, 0x4b}, - {0x4767, 0x0f}, - {0x4750, 0x14}, - {0x4540, 0x00}, - {0x47b4, 0x14}, - {0x4713, 0x30}, - {0x478b, 0x10}, - {0x478f, 0x10}, - {0x4793, 0x10}, - {0x4797, 0x0e}, - {0x479b, 0x0e}, }; static const struct imx219_reg raw8_framefmt_regs[] = { @@ -394,6 +306,10 @@ static const s64 imx219_link_freq_menu[] = { IMX219_DEFAULT_LINK_FREQ, }; +static const s64 imx219_link_freq_4lane_menu[] = { + IMX219_DEFAULT_LINK_FREQ_4LANE, +}; + static const char * const imx219_test_pattern_menu[] = { "Disabled", "Color Bars", @@ -485,6 +401,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), .regs = mode_3280x2464_regs, }, + .binning = false, }, { /* 1080P 30fps cropped */ @@ -501,6 +418,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), .regs = mode_1920_1080_regs, }, + .binning = false, }, { /* 2x2 binned 30fps mode */ @@ -517,6 +435,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), .regs = mode_1640_1232_regs, }, + .binning = true, }, { /* 640x480 30fps mode */ @@ -533,6 +452,7 @@ static const struct imx219_mode supported_modes[] = { .num_of_regs = ARRAY_SIZE(mode_640_480_regs), .regs = mode_640_480_regs, }, + .binning = true, }, }; @@ -569,6 +489,9 @@ struct imx219 { /* Streaming on/off */ bool streaming; + + /* Two or Four lanes */ + u8 lanes; }; static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd) @@ -979,6 +902,35 @@ static int imx219_set_framefmt(struct imx219 *imx219) return -EINVAL; } +static int imx219_set_binning(struct imx219 *imx219) +{ + if (!imx219->mode->binning) { + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, + IMX219_BINNING_NONE); + } + + switch (imx219->fmt.code) { + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SBGGR8_1X8: + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, + IMX219_BINNING_2X2_ANALOG); + + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, + IMX219_REG_VALUE_16BIT, + IMX219_BINNING_2X2); + } + + return -EINVAL; +} + static const struct v4l2_rect * __imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_state *sd_state, @@ -1031,6 +983,13 @@ static int imx219_get_selection(struct v4l2_subdev *sd, return -EINVAL; } +static int imx219_configure_lanes(struct imx219 *imx219) +{ + return imx219_write_reg(imx219, IMX219_REG_CSI_LANE_MODE, + IMX219_REG_VALUE_08BIT, (imx219->lanes == 2) ? + IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE); +}; + static int imx219_start_streaming(struct imx219 *imx219) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); @@ -1041,6 +1000,20 @@ static int imx219_start_streaming(struct imx219 *imx219) if (ret < 0) return ret; + /* Send all registers that are common to all modes */ + ret = imx219_write_regs(imx219, imx219_common_regs, ARRAY_SIZE(imx219_common_regs)); + if (ret) { + dev_err(&client->dev, "%s failed to send mfg header\n", __func__); + goto err_rpm_put; + } + + /* Configure two or four Lane mode */ + ret = imx219_configure_lanes(imx219); + if (ret) { + dev_err(&client->dev, "%s failed to configure lanes\n", __func__); + goto err_rpm_put; + } + /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); @@ -1056,6 +1029,13 @@ static int imx219_start_streaming(struct imx219 *imx219) goto err_rpm_put; } + ret = imx219_set_binning(imx219); + if (ret) { + dev_err(&client->dev, "%s failed to set binning: %d\n", + __func__, ret); + goto err_rpm_put; + } + /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); if (ret) @@ -1272,6 +1252,11 @@ static const struct v4l2_subdev_internal_ops imx219_internal_ops = { .open = imx219_open, }; +static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) +{ + return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; +} + /* Initialize control handlers */ static int imx219_init_controls(struct imx219 *imx219) { @@ -1293,15 +1278,16 @@ static int imx219_init_controls(struct imx219 *imx219) /* By default, PIXEL_RATE is read only */ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_PIXEL_RATE, - IMX219_PIXEL_RATE, - IMX219_PIXEL_RATE, 1, - IMX219_PIXEL_RATE); + imx219_get_pixel_rate(imx219), + imx219_get_pixel_rate(imx219), 1, + imx219_get_pixel_rate(imx219)); imx219->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_LINK_FREQ, ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, - imx219_link_freq_menu); + (imx219->lanes == 2) ? imx219_link_freq_menu : + imx219_link_freq_4lane_menu); if (imx219->link_freq) imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; @@ -1396,7 +1382,7 @@ static void imx219_free_controls(struct imx219 *imx219) mutex_destroy(&imx219->mutex); } -static int imx219_check_hwcfg(struct device *dev) +static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) { struct fwnode_handle *endpoint; struct v4l2_fwnode_endpoint ep_cfg = { @@ -1416,10 +1402,12 @@ static int imx219_check_hwcfg(struct device *dev) } /* Check the number of MIPI CSI2 data lanes */ - if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { - dev_err(dev, "only 2 data lanes are currently supported\n"); + if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2 && + ep_cfg.bus.mipi_csi2.num_data_lanes != 4) { + dev_err(dev, "only 2 or 4 data lanes are currently supported\n"); goto error_out; } + imx219->lanes = ep_cfg.bus.mipi_csi2.num_data_lanes; /* Check the link frequency set in device tree */ if (!ep_cfg.nr_of_link_frequencies) { @@ -1428,7 +1416,8 @@ static int imx219_check_hwcfg(struct device *dev) } if (ep_cfg.nr_of_link_frequencies != 1 || - ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) { + (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ? + IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) { dev_err(dev, "Link frequency not supported: %lld\n", ep_cfg.link_frequencies[0]); goto error_out; @@ -1456,7 +1445,7 @@ static int imx219_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); /* Check the hardware configuration in device tree */ - if (imx219_check_hwcfg(dev)) + if (imx219_check_hwcfg(dev, imx219)) return -EINVAL; /* Get system clock (xclk) */ diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 218ded13fd80..49d6c8bdec41 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -152,13 +152,10 @@ #define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920 #define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080 -static const char * const imx290_supply_name[] = { - "vdda", - "vddd", - "vdddo", -}; +/* Equivalent value for 16bpp */ +#define IMX290_BLACK_LEVEL_DEFAULT 3840 -#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name) +#define IMX290_NUM_SUPPLIES 3 struct imx290_regval { u32 reg; @@ -180,11 +177,10 @@ struct imx290 { struct clk *xclk; struct regmap *regmap; u8 nlanes; - u8 bpp; struct v4l2_subdev sd; struct media_pad pad; - struct v4l2_mbus_framefmt current_format; + const struct imx290_mode *current_mode; struct regulator_bulk_data supplies[IMX290_NUM_SUPPLIES]; @@ -195,35 +191,16 @@ struct imx290 { struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *hblank; struct v4l2_ctrl *vblank; - - struct mutex lock; -}; - -struct imx290_pixfmt { - u32 code; - u8 bpp; -}; - -static const struct imx290_pixfmt imx290_formats[] = { - { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, - { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, }; -static const struct regmap_config imx290_regmap_config = { - .reg_bits = 16, - .val_bits = 8, -}; +static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) +{ + return container_of(_sd, struct imx290, sd); +} -static const char * const imx290_test_pattern_menu[] = { - "Disabled", - "Sequence Pattern 1", - "Horizontal Color-bar Chart", - "Vertical Color-bar Chart", - "Sequence Pattern 2", - "Gradation Pattern 1", - "Gradation Pattern 2", - "000/555h Toggle Pattern", -}; +/* ----------------------------------------------------------------------------- + * Modes and formats + */ static const struct imx290_regval imx290_global_init_settings[] = { { IMX290_CTRL_07, IMX290_WINMODE_1080P }, @@ -338,7 +315,6 @@ static const struct imx290_regval imx290_10bit_settings[] = { { IMX290_ADBIT2, IMX290_ADBIT2_10BIT }, { IMX290_ADBIT3, IMX290_ADBIT3_10BIT }, { IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW10 }, - { IMX290_BLKLEVEL, 60 }, }; static const struct imx290_regval imx290_12bit_settings[] = { @@ -348,7 +324,6 @@ static const struct imx290_regval imx290_12bit_settings[] = { { IMX290_ADBIT2, IMX290_ADBIT2_12BIT }, { IMX290_ADBIT3, IMX290_ADBIT3_12BIT }, { IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW12 }, - { IMX290_BLKLEVEL, 240 }, }; /* supported link frequencies */ @@ -438,11 +413,45 @@ static inline int imx290_modes_num(const struct imx290 *imx290) return ARRAY_SIZE(imx290_modes_4lanes); } -static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) +struct imx290_format_info { + u32 code; + u8 bpp; + const struct imx290_regval *regs; + unsigned int num_regs; +}; + +static const struct imx290_format_info imx290_formats[] = { + { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .bpp = 10, + .regs = imx290_10bit_settings, + .num_regs = ARRAY_SIZE(imx290_10bit_settings), + }, { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .bpp = 12, + .regs = imx290_12bit_settings, + .num_regs = ARRAY_SIZE(imx290_12bit_settings), + } +}; + +static const struct imx290_format_info *imx290_format_info(u32 code) { - return container_of(_sd, struct imx290, sd); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx290_formats); ++i) { + const struct imx290_format_info *info = &imx290_formats[i]; + + if (info->code == code) + return info; + } + + return NULL; } +/* ----------------------------------------------------------------------------- + * Register access + */ + static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value) { u8 data[3] = { 0, 0, 0 }; @@ -501,28 +510,82 @@ static int imx290_set_register_array(struct imx290 *imx290, return 0; } -/* Stop streaming */ -static int imx290_stop_streaming(struct imx290 *imx290) +static int imx290_set_data_lanes(struct imx290 *imx290) { int ret = 0; + u32 frsel; - imx290_write(imx290, IMX290_STANDBY, 0x01, &ret); + switch (imx290->nlanes) { + case 2: + default: + frsel = 0x02; + break; + case 4: + frsel = 0x01; + break; + } - msleep(30); + imx290_write(imx290, IMX290_PHY_LANE_NUM, imx290->nlanes - 1, &ret); + imx290_write(imx290, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, &ret); + imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret); - return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret); + return ret; +} + +static int imx290_set_black_level(struct imx290 *imx290, + const struct v4l2_mbus_framefmt *format, + unsigned int black_level, int *err) +{ + unsigned int bpp = imx290_format_info(format->code)->bpp; + + return imx290_write(imx290, IMX290_BLKLEVEL, + black_level >> (16 - bpp), err); +} + +static int imx290_setup_format(struct imx290 *imx290, + const struct v4l2_mbus_framefmt *format) +{ + const struct imx290_format_info *info; + int ret; + + info = imx290_format_info(format->code); + + ret = imx290_set_register_array(imx290, info->regs, info->num_regs); + if (ret < 0) { + dev_err(imx290->dev, "Could not set format registers\n"); + return ret; + } + + return imx290_set_black_level(imx290, format, + IMX290_BLACK_LEVEL_DEFAULT, &ret); } +/* ---------------------------------------------------------------------------- + * Controls + */ + static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx290 *imx290 = container_of(ctrl->handler, struct imx290, ctrls); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; int ret = 0; + /* + * Return immediately for controls that don't need to be applied to the + * device. + */ + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) + return 0; + /* V4L2 controls values will be applied only when power is already up */ if (!pm_runtime_get_if_in_use(imx290->dev)) return 0; + state = v4l2_subdev_get_locked_active_state(&imx290->sd); + format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + switch (ctrl->id) { case V4L2_CID_ANALOGUE_GAIN: ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL); @@ -535,7 +598,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TEST_PATTERN: if (ctrl->val) { - imx290_write(imx290, IMX290_BLKLEVEL, 0, &ret); + imx290_set_black_level(imx290, format, 0, &ret); usleep_range(10000, 11000); imx290_write(imx290, IMX290_PGCTRL, (u8)(IMX290_PGCTRL_REGEN | @@ -544,20 +607,18 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) } else { imx290_write(imx290, IMX290_PGCTRL, 0x00, &ret); usleep_range(10000, 11000); - if (imx290->bpp == 10) - imx290_write(imx290, IMX290_BLKLEVEL, 0x3c, - &ret); - else /* 12 bits per pixel */ - imx290_write(imx290, IMX290_BLKLEVEL, 0xf0, - &ret); + imx290_set_black_level(imx290, format, + IMX290_BLACK_LEVEL_DEFAULT, &ret); } break; + default: ret = -EINVAL; break; } - pm_runtime_put(imx290->dev); + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); return ret; } @@ -566,14 +627,217 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = { .s_ctrl = imx290_set_ctrl, }; -static struct v4l2_mbus_framefmt * -imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state, - u32 which) +static const char * const imx290_test_pattern_menu[] = { + "Disabled", + "Sequence Pattern 1", + "Horizontal Color-bar Chart", + "Vertical Color-bar Chart", + "Sequence Pattern 2", + "Gradation Pattern 1", + "Gradation Pattern 2", + "000/555h Toggle Pattern", +}; + +static void imx290_ctrl_update(struct imx290 *imx290, + const struct v4l2_mbus_framefmt *format, + const struct imx290_mode *mode) { - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - return &imx290->current_format; - else - return v4l2_subdev_get_try_format(&imx290->sd, state, 0); + unsigned int hblank = mode->hmax - mode->width; + unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height; + s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index]; + u64 pixel_rate; + + /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = link_freq * 2 * imx290->nlanes; + do_div(pixel_rate, imx290_format_info(format->code)->bpp); + + __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, pixel_rate); + + __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, 1, hblank); + __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, 1, vblank); +} + +static int imx290_ctrl_init(struct imx290 *imx290) +{ + struct v4l2_fwnode_device_properties props; + int ret; + + ret = v4l2_fwnode_device_parse(imx290->dev, &props); + if (ret < 0) + return ret; + + v4l2_ctrl_handler_init(&imx290->ctrls, 9); + + /* + * The sensor has an analog gain and a digital gain, both controlled + * through a single gain value, expressed in 0.3dB increments. Values + * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values + * up to 72.0dB (240) add further digital gain. Limit the range to + * analog gain only, support for digital gain can be added separately + * if needed. + * + * The IMX327 and IMX462 are largely compatible with the IMX290, but + * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital + * gain. When support for those sensors gets added to the driver, the + * gain control should be adjusted accordingly. + */ + v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0); + + v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1, + IMX290_VMAX_DEFAULT - 2); + + /* + * Set the link frequency, pixel rate, horizontal blanking and vertical + * blanking to hardcoded values, they will be updated by + * imx290_ctrl_update(). + */ + imx290->link_freq = + v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_LINK_FREQ, + imx290_link_freqs_num(imx290) - 1, 0, + imx290_link_freqs_ptr(imx290)); + if (imx290->link_freq) + imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_PIXEL_RATE, + 1, INT_MAX, 1, 1); + + v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx290_test_pattern_menu) - 1, + 0, 0, imx290_test_pattern_menu); + + imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_HBLANK, 1, 1, 1, 1); + if (imx290->hblank) + imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_VBLANK, 1, 1, 1, 1); + if (imx290->vblank) + imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops, + &props); + + imx290->sd.ctrl_handler = &imx290->ctrls; + + if (imx290->ctrls.error) { + ret = imx290->ctrls.error; + v4l2_ctrl_handler_free(&imx290->ctrls); + return ret; + } + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Subdev operations + */ + +/* Start streaming */ +static int imx290_start_streaming(struct imx290 *imx290, + struct v4l2_subdev_state *state) +{ + const struct v4l2_mbus_framefmt *format; + int ret; + + /* Set init register settings */ + ret = imx290_set_register_array(imx290, imx290_global_init_settings, + ARRAY_SIZE( + imx290_global_init_settings)); + if (ret < 0) { + dev_err(imx290->dev, "Could not set init registers\n"); + return ret; + } + + /* Set data lane count */ + ret = imx290_set_data_lanes(imx290); + if (ret < 0) { + dev_err(imx290->dev, "Could not set data lanes\n"); + return ret; + } + + /* Apply the register values related to current frame format */ + format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + ret = imx290_setup_format(imx290, format); + if (ret < 0) { + dev_err(imx290->dev, "Could not set frame format\n"); + return ret; + } + + /* Apply default values of current mode */ + ret = imx290_set_register_array(imx290, imx290->current_mode->data, + imx290->current_mode->data_size); + if (ret < 0) { + dev_err(imx290->dev, "Could not set current mode\n"); + return ret; + } + + ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax, + NULL); + if (ret) + return ret; + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); + if (ret) { + dev_err(imx290->dev, "Could not sync v4l2 controls\n"); + return ret; + } + + imx290_write(imx290, IMX290_STANDBY, 0x00, &ret); + + msleep(30); + + /* Start streaming */ + return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret); +} + +/* Stop streaming */ +static int imx290_stop_streaming(struct imx290 *imx290) +{ + int ret = 0; + + imx290_write(imx290, IMX290_STANDBY, 0x01, &ret); + + msleep(30); + + return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret); +} + +static int imx290_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx290 *imx290 = to_imx290(sd); + struct v4l2_subdev_state *state; + int ret = 0; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (enable) { + ret = pm_runtime_resume_and_get(imx290->dev); + if (ret < 0) + goto unlock; + + ret = imx290_start_streaming(imx290, state); + if (ret) { + dev_err(imx290->dev, "Start stream failed\n"); + pm_runtime_put_sync(imx290->dev); + goto unlock; + } + } else { + imx290_stop_streaming(imx290); + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); + } + +unlock: + v4l2_subdev_unlock_state(state); + return ret; } static int imx290_enum_mbus_code(struct v4l2_subdev *sd, @@ -595,8 +859,7 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd, const struct imx290 *imx290 = to_imx290(sd); const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); - if ((fse->code != imx290_formats[0].code) && - (fse->code != imx290_formats[1].code)) + if (!imx290_format_info(fse->code)) return -EINVAL; if (fse->index >= imx290_modes_num(imx290)) @@ -610,47 +873,6 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int imx290_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx290 *imx290 = to_imx290(sd); - struct v4l2_mbus_framefmt *framefmt; - - mutex_lock(&imx290->lock); - - framefmt = imx290_get_pad_format(imx290, sd_state, fmt->which); - fmt->format = *framefmt; - - mutex_unlock(&imx290->lock); - - return 0; -} - -static inline u8 imx290_get_link_freq_index(struct imx290 *imx290) -{ - return imx290->current_mode->link_freq_index; -} - -static s64 imx290_get_link_freq(struct imx290 *imx290) -{ - u8 index = imx290_get_link_freq_index(imx290); - - return *(imx290_link_freqs_ptr(imx290) + index); -} - -static u64 imx290_calc_pixel_rate(struct imx290 *imx290) -{ - s64 link_freq = imx290_get_link_freq(imx290); - u8 nlanes = imx290->nlanes; - u64 pixel_rate; - - /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = link_freq * 2 * nlanes; - do_div(pixel_rate, imx290->bpp); - return pixel_rate; -} - static int imx290_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -658,9 +880,6 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, struct imx290 *imx290 = to_imx290(sd); const struct imx290_mode *mode; struct v4l2_mbus_framefmt *format; - unsigned int i; - - mutex_lock(&imx290->lock); mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290), imx290_modes_num(imx290), width, height, @@ -669,48 +888,21 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, fmt->format.width = mode->width; fmt->format.height = mode->height; - for (i = 0; i < ARRAY_SIZE(imx290_formats); i++) - if (imx290_formats[i].code == fmt->format.code) - break; - - if (i >= ARRAY_SIZE(imx290_formats)) - i = 0; + if (!imx290_format_info(fmt->format.code)) + fmt->format.code = imx290_formats[0].code; - fmt->format.code = imx290_formats[i].code; fmt->format.field = V4L2_FIELD_NONE; - format = imx290_get_pad_format(imx290, sd_state, fmt->which); + format = v4l2_subdev_get_pad_format(sd, sd_state, 0); if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { imx290->current_mode = mode; - imx290->bpp = imx290_formats[i].bpp; - - if (imx290->link_freq) - __v4l2_ctrl_s_ctrl(imx290->link_freq, - imx290_get_link_freq_index(imx290)); - if (imx290->pixel_rate) - __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, - imx290_calc_pixel_rate(imx290)); - - if (imx290->hblank) { - unsigned int hblank = mode->hmax - mode->width; - - __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, - 1, hblank); - } - - if (imx290->vblank) { - unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height; - __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, - 1, vblank); - } + imx290_ctrl_update(imx290, &fmt->format, mode); } *format = fmt->format; - mutex_unlock(&imx290->lock); - return 0; } @@ -718,14 +910,11 @@ static int imx290_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct imx290 *imx290 = to_imx290(sd); struct v4l2_mbus_framefmt *format; switch (sel->target) { case V4L2_SEL_TGT_CROP: { - format = imx290_get_pad_format(imx290, sd_state, sel->which); - - mutex_lock(&imx290->lock); + format = v4l2_subdev_get_pad_format(sd, sd_state, 0); sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2; @@ -734,7 +923,6 @@ static int imx290_get_selection(struct v4l2_subdev *sd, sel->r.width = format->width; sel->r.height = format->height; - mutex_unlock(&imx290->lock); return 0; } @@ -763,179 +951,116 @@ static int imx290_get_selection(struct v4l2_subdev *sd, static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - struct v4l2_subdev_format fmt = { 0 }; - - fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.format.width = 1920; - fmt.format.height = 1080; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .width = 1920, + .height = 1080, + }, + }; imx290_set_fmt(subdev, sd_state, &fmt); return 0; } -static int imx290_write_current_format(struct imx290 *imx290) -{ - int ret; +static const struct v4l2_subdev_video_ops imx290_video_ops = { + .s_stream = imx290_set_stream, +}; - switch (imx290->current_format.code) { - case MEDIA_BUS_FMT_SRGGB10_1X10: - ret = imx290_set_register_array(imx290, imx290_10bit_settings, - ARRAY_SIZE( - imx290_10bit_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set format registers\n"); - return ret; - } - break; - case MEDIA_BUS_FMT_SRGGB12_1X12: - ret = imx290_set_register_array(imx290, imx290_12bit_settings, - ARRAY_SIZE( - imx290_12bit_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set format registers\n"); - return ret; - } - break; - default: - dev_err(imx290->dev, "Unknown pixel format\n"); - return -EINVAL; - } +static const struct v4l2_subdev_pad_ops imx290_pad_ops = { + .init_cfg = imx290_entity_init_cfg, + .enum_mbus_code = imx290_enum_mbus_code, + .enum_frame_size = imx290_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = imx290_set_fmt, + .get_selection = imx290_get_selection, +}; - return 0; -} +static const struct v4l2_subdev_ops imx290_subdev_ops = { + .video = &imx290_video_ops, + .pad = &imx290_pad_ops, +}; -/* Start streaming */ -static int imx290_start_streaming(struct imx290 *imx290) +static const struct media_entity_operations imx290_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int imx290_subdev_init(struct imx290 *imx290) { + struct i2c_client *client = to_i2c_client(imx290->dev); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; int ret; - /* Set init register settings */ - ret = imx290_set_register_array(imx290, imx290_global_init_settings, - ARRAY_SIZE( - imx290_global_init_settings)); - if (ret < 0) { - dev_err(imx290->dev, "Could not set init registers\n"); - return ret; - } + imx290->current_mode = &imx290_modes_ptr(imx290)[0]; - /* Apply the register values related to current frame format */ - ret = imx290_write_current_format(imx290); + v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); + imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx290->sd.dev = imx290->dev; + imx290->sd.entity.ops = &imx290_subdev_entity_ops; + imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + imx290->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad); if (ret < 0) { - dev_err(imx290->dev, "Could not set frame format\n"); + dev_err(imx290->dev, "Could not register media entity\n"); return ret; } - /* Apply default values of current mode */ - ret = imx290_set_register_array(imx290, imx290->current_mode->data, - imx290->current_mode->data_size); + ret = imx290_ctrl_init(imx290); if (ret < 0) { - dev_err(imx290->dev, "Could not set current mode\n"); - return ret; + dev_err(imx290->dev, "Control initialization error %d\n", ret); + goto err_media; } - ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax, - NULL); - if (ret) - return ret; + imx290->sd.state_lock = imx290->ctrls.lock; - /* Apply customized values from user */ - ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); - if (ret) { - dev_err(imx290->dev, "Could not sync v4l2 controls\n"); - return ret; + ret = v4l2_subdev_init_finalize(&imx290->sd); + if (ret < 0) { + dev_err(imx290->dev, "subdev initialization error %d\n", ret); + goto err_ctrls; } - imx290_write(imx290, IMX290_STANDBY, 0x00, &ret); - - msleep(30); - - /* Start streaming */ - return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret); -} - -static int imx290_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct imx290 *imx290 = to_imx290(sd); - int ret = 0; + state = v4l2_subdev_lock_and_get_active_state(&imx290->sd); + format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); + imx290_ctrl_update(imx290, format, imx290->current_mode); + v4l2_subdev_unlock_state(state); - if (enable) { - ret = pm_runtime_resume_and_get(imx290->dev); - if (ret < 0) - goto unlock_and_return; - - ret = imx290_start_streaming(imx290); - if (ret) { - dev_err(imx290->dev, "Start stream failed\n"); - pm_runtime_put(imx290->dev); - goto unlock_and_return; - } - } else { - imx290_stop_streaming(imx290); - pm_runtime_put(imx290->dev); - } - -unlock_and_return: + return 0; +err_ctrls: + v4l2_ctrl_handler_free(&imx290->ctrls); +err_media: + media_entity_cleanup(&imx290->sd.entity); return ret; } -static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) +static void imx290_subdev_cleanup(struct imx290 *imx290) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++) - imx290->supplies[i].supply = imx290_supply_name[i]; - - return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies), - imx290->supplies); + v4l2_subdev_cleanup(&imx290->sd); + media_entity_cleanup(&imx290->sd.entity); + v4l2_ctrl_handler_free(&imx290->ctrls); } -static int imx290_set_data_lanes(struct imx290 *imx290) -{ - int ret = 0, laneval, frsel; - - switch (imx290->nlanes) { - case 2: - laneval = 0x01; - frsel = 0x02; - break; - case 4: - laneval = 0x03; - frsel = 0x01; - break; - default: - /* - * We should never hit this since the data lane count is - * validated in probe itself - */ - dev_err(imx290->dev, "Lane configuration not supported\n"); - return -EINVAL; - } - - imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret); - imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret); - imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret); - - return ret; -} +/* ---------------------------------------------------------------------------- + * Power management + */ -static int imx290_power_on(struct device *dev) +static int imx290_power_on(struct imx290 *imx290) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx290 *imx290 = to_imx290(sd); int ret; ret = clk_prepare_enable(imx290->xclk); if (ret) { - dev_err(dev, "Failed to enable clock\n"); + dev_err(imx290->dev, "Failed to enable clock\n"); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(imx290->supplies), imx290->supplies); if (ret) { - dev_err(dev, "Failed to enable regulators\n"); + dev_err(imx290->dev, "Failed to enable regulators\n"); clk_disable_unprepare(imx290->xclk); return ret; } @@ -944,123 +1069,86 @@ static int imx290_power_on(struct device *dev) gpiod_set_value_cansleep(imx290->rst_gpio, 0); usleep_range(30000, 31000); - /* Set data lane count */ - imx290_set_data_lanes(imx290); - return 0; } -static int imx290_power_off(struct device *dev) +static void imx290_power_off(struct imx290 *imx290) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx290 *imx290 = to_imx290(sd); - clk_disable_unprepare(imx290->xclk); gpiod_set_value_cansleep(imx290->rst_gpio, 1); regulator_bulk_disable(ARRAY_SIZE(imx290->supplies), imx290->supplies); +} + +static int imx290_runtime_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx290 *imx290 = to_imx290(sd); + + return imx290_power_on(imx290); +} + +static int imx290_runtime_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx290 *imx290 = to_imx290(sd); + + imx290_power_off(imx290); return 0; } static const struct dev_pm_ops imx290_pm_ops = { - SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL) -}; - -static const struct v4l2_subdev_video_ops imx290_video_ops = { - .s_stream = imx290_set_stream, + SET_RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL) }; -static const struct v4l2_subdev_pad_ops imx290_pad_ops = { - .init_cfg = imx290_entity_init_cfg, - .enum_mbus_code = imx290_enum_mbus_code, - .enum_frame_size = imx290_enum_frame_size, - .get_fmt = imx290_get_fmt, - .set_fmt = imx290_set_fmt, - .get_selection = imx290_get_selection, -}; +/* ---------------------------------------------------------------------------- + * Probe & remove + */ -static const struct v4l2_subdev_ops imx290_subdev_ops = { - .video = &imx290_video_ops, - .pad = &imx290_pad_ops, +static const struct regmap_config imx290_regmap_config = { + .reg_bits = 16, + .val_bits = 8, }; -static const struct media_entity_operations imx290_subdev_entity_ops = { - .link_validate = v4l2_subdev_link_validate, +static const char * const imx290_supply_name[IMX290_NUM_SUPPLIES] = { + "vdda", + "vddd", + "vdddo", }; -static int imx290_ctrl_init(struct imx290 *imx290) +static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) { - struct v4l2_fwnode_device_properties props; - unsigned int blank; - int ret; - - ret = v4l2_fwnode_device_parse(imx290->dev, &props); - if (ret < 0) - return ret; - - v4l2_ctrl_handler_init(&imx290->ctrls, 9); - imx290->ctrls.lock = &imx290->lock; - - /* - * The sensor has an analog gain and a digital gain, both controlled - * through a single gain value, expressed in 0.3dB increments. Values - * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values - * up to 72.0dB (240) add further digital gain. Limit the range to - * analog gain only, support for digital gain can be added separately - * if needed. - * - * The IMX327 and IMX462 are largely compatible with the IMX290, but - * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital - * gain. When support for those sensors gets added to the driver, the - * gain control should be adjusted accordingly. - */ - v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0); - - v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1, - IMX290_VMAX_DEFAULT - 2); - - imx290->link_freq = - v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_LINK_FREQ, - imx290_link_freqs_num(imx290) - 1, 0, - imx290_link_freqs_ptr(imx290)); - if (imx290->link_freq) - imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - - imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_PIXEL_RATE, - 1, INT_MAX, 1, - imx290_calc_pixel_rate(imx290)); + unsigned int i; - v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(imx290_test_pattern_menu) - 1, - 0, 0, imx290_test_pattern_menu); + for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++) + imx290->supplies[i].supply = imx290_supply_name[i]; - blank = imx290->current_mode->hmax - imx290->current_mode->width; - imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_HBLANK, blank, blank, 1, - blank); - if (imx290->hblank) - imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies), + imx290->supplies); +} - blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height; - imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, - V4L2_CID_VBLANK, blank, blank, 1, - blank); - if (imx290->vblank) - imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; +static int imx290_init_clk(struct imx290 *imx290) +{ + u32 xclk_freq; + int ret; - v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops, - &props); + ret = fwnode_property_read_u32(dev_fwnode(imx290->dev), + "clock-frequency", &xclk_freq); + if (ret) { + dev_err(imx290->dev, "Could not get xclk frequency\n"); + return ret; + } - imx290->sd.ctrl_handler = &imx290->ctrls; + /* external clock must be 37.125 MHz */ + if (xclk_freq != 37125000) { + dev_err(imx290->dev, "External clock frequency %u is not supported\n", + xclk_freq); + return -EINVAL; + } - if (imx290->ctrls.error) { - ret = imx290->ctrls.error; - v4l2_ctrl_handler_free(&imx290->ctrls); + ret = clk_set_rate(imx290->xclk, xclk_freq); + if (ret) { + dev_err(imx290->dev, "Could not set xclk frequency\n"); return ret; } @@ -1089,171 +1177,159 @@ static s64 imx290_check_link_freqs(const struct imx290 *imx290, return 0; } -static int imx290_probe(struct i2c_client *client) +static int imx290_parse_dt(struct imx290 *imx290) { - struct device *dev = &client->dev; - struct fwnode_handle *endpoint; /* Only CSI2 is supported for now: */ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - struct imx290 *imx290; - u32 xclk_freq; - s64 fq; + struct fwnode_handle *endpoint; int ret; + s64 fq; - imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); - if (!imx290) - return -ENOMEM; - - imx290->dev = dev; - imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config); - if (IS_ERR(imx290->regmap)) { - dev_err(dev, "Unable to initialize I2C\n"); - return -ENODEV; - } - - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx290->dev), NULL); if (!endpoint) { - dev_err(dev, "Endpoint node not found\n"); + dev_err(imx290->dev, "Endpoint node not found\n"); return -EINVAL; } ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); fwnode_handle_put(endpoint); if (ret == -ENXIO) { - dev_err(dev, "Unsupported bus type, should be CSI2\n"); - goto free_err; + dev_err(imx290->dev, "Unsupported bus type, should be CSI2\n"); + goto done; } else if (ret) { - dev_err(dev, "Parsing endpoint node failed\n"); - goto free_err; + dev_err(imx290->dev, "Parsing endpoint node failed\n"); + goto done; } /* Get number of data lanes */ imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes; if (imx290->nlanes != 2 && imx290->nlanes != 4) { - dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes); + dev_err(imx290->dev, "Invalid data lanes: %d\n", imx290->nlanes); ret = -EINVAL; - goto free_err; + goto done; } - dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); + dev_dbg(imx290->dev, "Using %u data lanes\n", imx290->nlanes); if (!ep.nr_of_link_frequencies) { - dev_err(dev, "link-frequency property not found in DT\n"); + dev_err(imx290->dev, "link-frequency property not found in DT\n"); ret = -EINVAL; - goto free_err; + goto done; } /* Check that link frequences for all the modes are in device tree */ fq = imx290_check_link_freqs(imx290, &ep); if (fq) { - dev_err(dev, "Link frequency of %lld is not supported\n", fq); + dev_err(imx290->dev, "Link frequency of %lld is not supported\n", + fq); ret = -EINVAL; - goto free_err; + goto done; } - /* get system clock (xclk) */ - imx290->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(imx290->xclk)) { - dev_err(dev, "Could not get xclk"); - ret = PTR_ERR(imx290->xclk); - goto free_err; - } + ret = 0; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &xclk_freq); - if (ret) { - dev_err(dev, "Could not get xclk frequency\n"); - goto free_err; - } +done: + v4l2_fwnode_endpoint_free(&ep); + return ret; +} - /* external clock must be 37.125 MHz */ - if (xclk_freq != 37125000) { - dev_err(dev, "External clock frequency %u is not supported\n", - xclk_freq); - ret = -EINVAL; - goto free_err; - } +static int imx290_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct imx290 *imx290; + int ret; - ret = clk_set_rate(imx290->xclk, xclk_freq); - if (ret) { - dev_err(dev, "Could not set xclk frequency\n"); - goto free_err; + imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); + if (!imx290) + return -ENOMEM; + + imx290->dev = dev; + imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config); + if (IS_ERR(imx290->regmap)) { + dev_err(dev, "Unable to initialize I2C\n"); + return -ENODEV; } + ret = imx290_parse_dt(imx290); + if (ret) + return ret; + + /* Acquire resources. */ + imx290->xclk = devm_clk_get(dev, "xclk"); + if (IS_ERR(imx290->xclk)) + return dev_err_probe(dev, PTR_ERR(imx290->xclk), + "Could not get xclk"); + ret = imx290_get_regulators(dev, imx290); - if (ret < 0) { - dev_err(dev, "Cannot get regulators\n"); - goto free_err; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot get regulators\n"); imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(imx290->rst_gpio)) { - dev_err(dev, "Cannot get reset gpio\n"); - ret = PTR_ERR(imx290->rst_gpio); - goto free_err; - } + if (IS_ERR(imx290->rst_gpio)) + return dev_err_probe(dev, PTR_ERR(imx290->rst_gpio), + "Cannot get reset gpio\n"); - mutex_init(&imx290->lock); + /* Initialize external clock frequency. */ + ret = imx290_init_clk(imx290); + if (ret) + return ret; /* - * Initialize the frame format. In particular, imx290->current_mode - * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call - * below relies on these fields. + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here. */ - imx290_entity_init_cfg(&imx290->sd, NULL); - - ret = imx290_ctrl_init(imx290); + ret = imx290_power_on(imx290); if (ret < 0) { - dev_err(dev, "Control initialization error %d\n", ret); - goto free_mutex; + dev_err(dev, "Could not power on the device\n"); + return ret; } - v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); - imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - imx290->sd.dev = &client->dev; - imx290->sd.entity.ops = &imx290_subdev_entity_ops; - imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + /* + * Enable runtime PM with autosuspend. As the device has been powered + * manually, mark it as active, and increase the usage count without + * resuming the device. + */ + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); - imx290->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad); - if (ret < 0) { - dev_err(dev, "Could not register media entity\n"); - goto free_ctrl; - } + /* Initialize the V4L2 subdev. */ + ret = imx290_subdev_init(imx290); + if (ret) + goto err_pm; + /* + * Finally, register the V4L2 subdev. This must be done after + * initializing everything as the subdev can be used immediately after + * being registered. + */ ret = v4l2_async_register_subdev(&imx290->sd); if (ret < 0) { dev_err(dev, "Could not register v4l2 device\n"); - goto free_entity; - } - - /* Power on the device to match runtime PM state below */ - ret = imx290_power_on(dev); - if (ret < 0) { - dev_err(dev, "Could not power on the device\n"); - goto free_entity; + goto err_subdev; } - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); - - v4l2_fwnode_endpoint_free(&ep); + /* + * Decrease the PM usage count. The device will get suspended after the + * autosuspend delay, turning the power off. + */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; -free_entity: - media_entity_cleanup(&imx290->sd.entity); -free_ctrl: - v4l2_ctrl_handler_free(&imx290->ctrls); -free_mutex: - mutex_destroy(&imx290->lock); -free_err: - v4l2_fwnode_endpoint_free(&ep); - +err_subdev: + imx290_subdev_cleanup(imx290); +err_pm: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + imx290_power_off(imx290); return ret; } @@ -1263,14 +1339,15 @@ static void imx290_remove(struct i2c_client *client) struct imx290 *imx290 = to_imx290(sd); v4l2_async_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); - v4l2_ctrl_handler_free(sd->ctrl_handler); - - mutex_destroy(&imx290->lock); + imx290_subdev_cleanup(imx290); + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ pm_runtime_disable(imx290->dev); if (!pm_runtime_status_suspended(imx290->dev)) - imx290_power_off(imx290->dev); + imx290_power_off(imx290); pm_runtime_set_suspended(imx290->dev); } diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c new file mode 100644 index 000000000000..3c12b6edeac9 --- /dev/null +++ b/drivers/media/i2c/imx296.c @@ -0,0 +1,1172 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for IMX296 CMOS Image Sensor from Sony + * + * Copyright 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#include <linux/clk.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/videodev2.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +#define IMX296_PIXEL_ARRAY_WIDTH 1456 +#define IMX296_PIXEL_ARRAY_HEIGHT 1088 + +#define IMX296_REG_8BIT(n) ((1 << 16) | (n)) +#define IMX296_REG_16BIT(n) ((2 << 16) | (n)) +#define IMX296_REG_24BIT(n) ((3 << 16) | (n)) +#define IMX296_REG_SIZE_SHIFT 16 +#define IMX296_REG_ADDR_MASK 0xffff + +#define IMX296_CTRL00 IMX296_REG_8BIT(0x3000) +#define IMX296_CTRL00_STANDBY BIT(0) +#define IMX296_CTRL08 IMX296_REG_8BIT(0x3008) +#define IMX296_CTRL08_REGHOLD BIT(0) +#define IMX296_CTRL0A IMX296_REG_8BIT(0x300a) +#define IMX296_CTRL0A_XMSTA BIT(0) +#define IMX296_CTRL0B IMX296_REG_8BIT(0x300b) +#define IMX296_CTRL0B_TRIGEN BIT(0) +#define IMX296_CTRL0D IMX296_REG_8BIT(0x300d) +#define IMX296_CTRL0D_WINMODE_ALL (0 << 0) +#define IMX296_CTRL0D_WINMODE_FD_BINNING (2 << 0) +#define IMX296_CTRL0D_HADD_ON_BINNING BIT(5) +#define IMX296_CTRL0D_SAT_CNT BIT(6) +#define IMX296_CTRL0E IMX296_REG_8BIT(0x300e) +#define IMX296_CTRL0E_VREVERSE BIT(0) +#define IMX296_CTRL0E_HREVERSE BIT(1) +#define IMX296_VMAX IMX296_REG_24BIT(0x3010) +#define IMX296_HMAX IMX296_REG_16BIT(0x3014) +#define IMX296_TMDCTRL IMX296_REG_8BIT(0x301d) +#define IMX296_TMDCTRL_LATCH BIT(0) +#define IMX296_TMDOUT IMX296_REG_16BIT(0x301e) +#define IMX296_TMDOUT_MASK 0x3ff +#define IMX296_WDSEL IMX296_REG_8BIT(0x3021) +#define IMX296_WDSEL_NORMAL (0 << 0) +#define IMX296_WDSEL_MULTI_2 (1 << 0) +#define IMX296_WDSEL_MULTI_4 (3 << 0) +#define IMX296_BLKLEVELAUTO IMX296_REG_8BIT(0x3022) +#define IMX296_BLKLEVELAUTO_ON 0x01 +#define IMX296_BLKLEVELAUTO_OFF 0xf0 +#define IMX296_SST IMX296_REG_8BIT(0x3024) +#define IMX296_SST_EN BIT(0) +#define IMX296_CTRLTOUT IMX296_REG_8BIT(0x3026) +#define IMX296_CTRLTOUT_TOUT1SEL_LOW (0 << 0) +#define IMX296_CTRLTOUT_TOUT1SEL_PULSE (3 << 0) +#define IMX296_CTRLTOUT_TOUT2SEL_LOW (0 << 2) +#define IMX296_CTRLTOUT_TOUT2SEL_PULSE (3 << 2) +#define IMX296_CTRLTRIG IMX296_REG_8BIT(0x3029) +#define IMX296_CTRLTRIG_TOUT1_SEL_LOW (0 << 0) +#define IMX296_CTRLTRIG_TOUT1_SEL_PULSE1 (1 << 0) +#define IMX296_CTRLTRIG_TOUT2_SEL_LOW (0 << 4) +#define IMX296_CTRLTRIG_TOUT2_SEL_PULSE2 (2 << 4) +#define IMX296_SYNCSEL IMX296_REG_8BIT(0x3036) +#define IMX296_SYNCSEL_NORMAL 0xc0 +#define IMX296_SYNCSEL_HIZ 0xf0 +#define IMX296_PULSE1 IMX296_REG_8BIT(0x306d) +#define IMX296_PULSE1_EN_NOR BIT(0) +#define IMX296_PULSE1_EN_TRIG BIT(1) +#define IMX296_PULSE1_POL_HIGH (0 << 2) +#define IMX296_PULSE1_POL_LOW (1 << 2) +#define IMX296_PULSE1_UP IMX296_REG_24BIT(0x3070) +#define IMX296_PULSE1_DN IMX296_REG_24BIT(0x3074) +#define IMX296_PULSE2 IMX296_REG_8BIT(0x3079) +#define IMX296_PULSE2_EN_NOR BIT(0) +#define IMX296_PULSE2_EN_TRIG BIT(1) +#define IMX296_PULSE2_POL_HIGH (0 << 2) +#define IMX296_PULSE2_POL_LOW (1 << 2) +#define IMX296_PULSE2_UP IMX296_REG_24BIT(0x307c) +#define IMX296_PULSE2_DN IMX296_REG_24BIT(0x3080) +#define IMX296_INCKSEL(n) IMX296_REG_8BIT(0x3089 + (n)) +#define IMX296_SHS1 IMX296_REG_24BIT(0x308d) +#define IMX296_SHS2 IMX296_REG_24BIT(0x3090) +#define IMX296_SHS3 IMX296_REG_24BIT(0x3094) +#define IMX296_SHS4 IMX296_REG_24BIT(0x3098) +#define IMX296_VBLANKLP IMX296_REG_8BIT(0x309c) +#define IMX296_VBLANKLP_NORMAL 0x04 +#define IMX296_VBLANKLP_LOW_POWER 0x2c +#define IMX296_EXP_CNT IMX296_REG_8BIT(0x30a3) +#define IMX296_EXP_CNT_RESET BIT(0) +#define IMX296_EXP_MAX IMX296_REG_16BIT(0x30a6) +#define IMX296_VINT IMX296_REG_8BIT(0x30aa) +#define IMX296_VINT_EN BIT(0) +#define IMX296_LOWLAGTRG IMX296_REG_8BIT(0x30ae) +#define IMX296_LOWLAGTRG_FAST BIT(0) +#define IMX296_I2CCTRL IMX296_REG_8BIT(0x30ef) +#define IMX296_I2CCTRL_I2CACKEN BIT(0) + +#define IMX296_SENSOR_INFO IMX296_REG_16BIT(0x3148) +#define IMX296_SENSOR_INFO_MONO BIT(15) +#define IMX296_SENSOR_INFO_IMX296LQ 0x4a00 +#define IMX296_SENSOR_INFO_IMX296LL 0xca00 +#define IMX296_S_SHSA IMX296_REG_16BIT(0x31ca) +#define IMX296_S_SHSB IMX296_REG_16BIT(0x31d2) +/* + * Registers 0x31c8 to 0x31cd, 0x31d0 to 0x31d5, 0x31e2, 0x31e3, 0x31ea and + * 0x31eb are related to exposure mode but otherwise not documented. + */ + +#define IMX296_GAINCTRL IMX296_REG_8BIT(0x3200) +#define IMX296_GAINCTRL_WD_GAIN_MODE_NORMAL 0x01 +#define IMX296_GAINCTRL_WD_GAIN_MODE_MULTI 0x41 +#define IMX296_GAIN IMX296_REG_16BIT(0x3204) +#define IMX296_GAIN_MIN 0 +#define IMX296_GAIN_MAX 480 +#define IMX296_GAIN1 IMX296_REG_16BIT(0x3208) +#define IMX296_GAIN2 IMX296_REG_16BIT(0x320c) +#define IMX296_GAIN3 IMX296_REG_16BIT(0x3210) +#define IMX296_GAINDLY IMX296_REG_8BIT(0x3212) +#define IMX296_GAINDLY_NONE 0x08 +#define IMX296_GAINDLY_1FRAME 0x09 +#define IMX296_PGCTRL IMX296_REG_8BIT(0x3238) +#define IMX296_PGCTRL_REGEN BIT(0) +#define IMX296_PGCTRL_THRU BIT(1) +#define IMX296_PGCTRL_CLKEN BIT(2) +#define IMX296_PGCTRL_MODE(n) ((n) << 3) +#define IMX296_PGHPOS IMX296_REG_16BIT(0x3239) +#define IMX296_PGVPOS IMX296_REG_16BIT(0x323c) +#define IMX296_PGHPSTEP IMX296_REG_8BIT(0x323e) +#define IMX296_PGVPSTEP IMX296_REG_8BIT(0x323f) +#define IMX296_PGHPNUM IMX296_REG_8BIT(0x3240) +#define IMX296_PGVPNUM IMX296_REG_8BIT(0x3241) +#define IMX296_PGDATA1 IMX296_REG_16BIT(0x3244) +#define IMX296_PGDATA2 IMX296_REG_16BIT(0x3246) +#define IMX296_PGHGSTEP IMX296_REG_8BIT(0x3249) +#define IMX296_BLKLEVEL IMX296_REG_16BIT(0x3254) + +#define IMX296_FID0_ROI IMX296_REG_8BIT(0x3300) +#define IMX296_FID0_ROIH1ON BIT(0) +#define IMX296_FID0_ROIV1ON BIT(1) +#define IMX296_FID0_ROIPH1 IMX296_REG_16BIT(0x3310) +#define IMX296_FID0_ROIPV1 IMX296_REG_16BIT(0x3312) +#define IMX296_FID0_ROIWH1 IMX296_REG_16BIT(0x3314) +#define IMX296_FID0_ROIWH1_MIN 80 +#define IMX296_FID0_ROIWV1 IMX296_REG_16BIT(0x3316) +#define IMX296_FID0_ROIWV1_MIN 4 + +#define IMX296_CM_HSST_STARTTMG IMX296_REG_16BIT(0x4018) +#define IMX296_CM_HSST_ENDTMG IMX296_REG_16BIT(0x401a) +#define IMX296_DA_HSST_STARTTMG IMX296_REG_16BIT(0x404d) +#define IMX296_DA_HSST_ENDTMG IMX296_REG_16BIT(0x4050) +#define IMX296_LM_HSST_STARTTMG IMX296_REG_16BIT(0x4094) +#define IMX296_LM_HSST_ENDTMG IMX296_REG_16BIT(0x4096) +#define IMX296_SST_SIEASTA1_SET IMX296_REG_8BIT(0x40c9) +#define IMX296_SST_SIEASTA1PRE_1U IMX296_REG_16BIT(0x40cc) +#define IMX296_SST_SIEASTA1PRE_1D IMX296_REG_16BIT(0x40ce) +#define IMX296_SST_SIEASTA1PRE_2U IMX296_REG_16BIT(0x40d0) +#define IMX296_SST_SIEASTA1PRE_2D IMX296_REG_16BIT(0x40d2) +#define IMX296_HSST IMX296_REG_8BIT(0x40dc) +#define IMX296_HSST_EN BIT(2) + +#define IMX296_CKREQSEL IMX296_REG_8BIT(0x4101) +#define IMX296_CKREQSEL_HS BIT(2) +#define IMX296_GTTABLENUM IMX296_REG_8BIT(0x4114) +#define IMX296_CTRL418C IMX296_REG_8BIT(0x418c) + +struct imx296_clk_params { + unsigned int freq; + u8 incksel[4]; + u8 ctrl418c; +}; + +static const struct imx296_clk_params imx296_clk_params[] = { + { 37125000, { 0x80, 0x0b, 0x80, 0x08 }, 116 }, + { 54000000, { 0xb0, 0x0f, 0xb0, 0x0c }, 168 }, + { 74250000, { 0x80, 0x0f, 0x80, 0x0c }, 232 }, +}; + +static const char * const imx296_supply_names[] = { + "dvdd", + "ovdd", + "avdd", +}; + +struct imx296 { + struct device *dev; + struct clk *clk; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx296_supply_names)]; + struct gpio_desc *reset; + struct regmap *regmap; + + const struct imx296_clk_params *clk_params; + bool mono; + + bool streaming; + + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; +}; + +static inline struct imx296 *to_imx296(struct v4l2_subdev *sd) +{ + return container_of(sd, struct imx296, subdev); +} + +static int imx296_read(struct imx296 *sensor, u32 addr) +{ + u8 data[3] = { 0, 0, 0 }; + int ret; + + ret = regmap_raw_read(sensor->regmap, addr & IMX296_REG_ADDR_MASK, data, + (addr >> IMX296_REG_SIZE_SHIFT) & 3); + if (ret < 0) + return ret; + + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + +static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err) +{ + u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 }; + int ret; + + if (err && *err) + return *err; + + ret = regmap_raw_write(sensor->regmap, addr & IMX296_REG_ADDR_MASK, + data, (addr >> IMX296_REG_SIZE_SHIFT) & 3); + if (ret < 0) { + dev_err(sensor->dev, "%u-bit write to 0x%04x failed: %d\n", + ((addr >> IMX296_REG_SIZE_SHIFT) & 3) * 8, + addr & IMX296_REG_ADDR_MASK, ret); + if (err) + *err = ret; + } + + return ret; +} + +static int imx296_power_on(struct imx296 *sensor) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) + return ret; + + udelay(1); + + ret = gpiod_direction_output(sensor->reset, 0); + if (ret < 0) + goto err_supply; + + udelay(1); + + ret = clk_prepare_enable(sensor->clk); + if (ret < 0) + goto err_reset; + + /* + * The documentation doesn't explicitly say how much time is required + * after providing a clock and before starting I2C communication. It + * mentions a delay of 20µs in 4-wire mode, but tests showed that a + * delay of 100µs resulted in I2C communication failures, while 500µs + * seems to be enough. Be conservative. + */ + usleep_range(1000, 2000); + + return 0; + +err_reset: + gpiod_direction_output(sensor->reset, 1); +err_supply: + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); + return ret; +} + +static void imx296_power_off(struct imx296 *sensor) +{ + clk_disable_unprepare(sensor->clk); + gpiod_direction_output(sensor->reset, 1); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); +} + +/* ----------------------------------------------------------------------------- + * Controls + */ + +static const char * const imx296_test_pattern_menu[] = { + "Disabled", + "Multiple Pixels", + "Sequence 1", + "Sequence 2", + "Gradient", + "Row", + "Column", + "Cross", + "Stripe", + "Checks", +}; + +static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx296 *sensor = container_of(ctrl->handler, struct imx296, ctrls); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + unsigned int vmax; + int ret = 0; + + if (!sensor->streaming) + return 0; + + state = v4l2_subdev_get_locked_active_state(&sensor->subdev); + format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* Clamp the exposure value to VMAX. */ + vmax = format->height + sensor->vblank->cur.val; + ctrl->val = min_t(int, ctrl->val, vmax); + imx296_write(sensor, IMX296_SHS1, vmax - ctrl->val, &ret); + break; + + case V4L2_CID_ANALOGUE_GAIN: + imx296_write(sensor, IMX296_GAIN, ctrl->val, &ret); + break; + + case V4L2_CID_VBLANK: + imx296_write(sensor, IMX296_VMAX, format->height + ctrl->val, + &ret); + break; + + case V4L2_CID_TEST_PATTERN: + if (ctrl->val) { + imx296_write(sensor, IMX296_PGHPOS, 8, &ret); + imx296_write(sensor, IMX296_PGVPOS, 8, &ret); + imx296_write(sensor, IMX296_PGHPSTEP, 8, &ret); + imx296_write(sensor, IMX296_PGVPSTEP, 8, &ret); + imx296_write(sensor, IMX296_PGHPNUM, 100, &ret); + imx296_write(sensor, IMX296_PGVPNUM, 100, &ret); + imx296_write(sensor, IMX296_PGDATA1, 0x300, &ret); + imx296_write(sensor, IMX296_PGDATA2, 0x100, &ret); + imx296_write(sensor, IMX296_PGHGSTEP, 0, &ret); + imx296_write(sensor, IMX296_BLKLEVEL, 0, &ret); + imx296_write(sensor, IMX296_BLKLEVELAUTO, + IMX296_BLKLEVELAUTO_OFF, &ret); + imx296_write(sensor, IMX296_PGCTRL, + IMX296_PGCTRL_REGEN | + IMX296_PGCTRL_CLKEN | + IMX296_PGCTRL_MODE(ctrl->val - 1), &ret); + } else { + imx296_write(sensor, IMX296_PGCTRL, + IMX296_PGCTRL_CLKEN, &ret); + imx296_write(sensor, IMX296_BLKLEVEL, 0x3c, &ret); + imx296_write(sensor, IMX296_BLKLEVELAUTO, + IMX296_BLKLEVELAUTO_ON, &ret); + } + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static const struct v4l2_ctrl_ops imx296_ctrl_ops = { + .s_ctrl = imx296_s_ctrl, +}; + +static int imx296_ctrls_init(struct imx296 *sensor) +{ + struct v4l2_fwnode_device_properties props; + unsigned int hblank; + int ret; + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret < 0) + return ret; + + v4l2_ctrl_handler_init(&sensor->ctrls, 9); + + v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 1048575, 1, 1104); + v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, IMX296_GAIN_MIN, + IMX296_GAIN_MAX, 1, IMX296_GAIN_MIN); + + /* + * Horizontal blanking is controlled through the HMAX register, which + * contains a line length in INCK clock units. The INCK frequency is + * fixed to 74.25 MHz. The HMAX value is currently fixed to 1100, + * convert it to a number of pixels based on the nominal pixel rate. + */ + hblank = 1100 * 1188000000ULL / 10 / 74250000 + - IMX296_PIXEL_ARRAY_WIDTH; + sensor->hblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, 1, + hblank); + if (sensor->hblank) + sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_VBLANK, 30, + 1048575 - IMX296_PIXEL_ARRAY_HEIGHT, + 1, 30); + /* + * The sensor calculates the MIPI timings internally to achieve a bit + * rate between 1122 and 1198 Mbps. The exact value is unfortunately not + * reported, at least according to the documentation. Report a nominal + * rate of 1188 Mbps as that is used by the datasheet in multiple + * examples. + */ + v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, + 1122000000 / 10, 1198000000 / 10, 1, 1188000000 / 10); + v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx296_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx296_test_pattern_menu) - 1, + 0, 0, imx296_test_pattern_menu); + + v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx296_ctrl_ops, + &props); + + if (sensor->ctrls.error) { + dev_err(sensor->dev, "failed to add controls (%d)\n", + sensor->ctrls.error); + v4l2_ctrl_handler_free(&sensor->ctrls); + return sensor->ctrls.error; + } + + sensor->subdev.ctrl_handler = &sensor->ctrls; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdev Operations + */ + +/* + * This table is extracted from vendor data that is entirely undocumented. The + * first register write is required to activate the CSI-2 output. The other + * entries may or may not be optional? + */ +static const struct { + unsigned int reg; + unsigned int value; +} imx296_init_table[] = { + { IMX296_REG_8BIT(0x3005), 0xf0 }, + { IMX296_REG_8BIT(0x309e), 0x04 }, + { IMX296_REG_8BIT(0x30a0), 0x04 }, + { IMX296_REG_8BIT(0x30a1), 0x3c }, + { IMX296_REG_8BIT(0x30a4), 0x5f }, + { IMX296_REG_8BIT(0x30a8), 0x91 }, + { IMX296_REG_8BIT(0x30ac), 0x28 }, + { IMX296_REG_8BIT(0x30af), 0x09 }, + { IMX296_REG_8BIT(0x30df), 0x00 }, + { IMX296_REG_8BIT(0x3165), 0x00 }, + { IMX296_REG_8BIT(0x3169), 0x10 }, + { IMX296_REG_8BIT(0x316a), 0x02 }, + { IMX296_REG_8BIT(0x31c8), 0xf3 }, /* Exposure-related */ + { IMX296_REG_8BIT(0x31d0), 0xf4 }, /* Exposure-related */ + { IMX296_REG_8BIT(0x321a), 0x00 }, + { IMX296_REG_8BIT(0x3226), 0x02 }, + { IMX296_REG_8BIT(0x3256), 0x01 }, + { IMX296_REG_8BIT(0x3541), 0x72 }, + { IMX296_REG_8BIT(0x3516), 0x77 }, + { IMX296_REG_8BIT(0x350b), 0x7f }, + { IMX296_REG_8BIT(0x3758), 0xa3 }, + { IMX296_REG_8BIT(0x3759), 0x00 }, + { IMX296_REG_8BIT(0x375a), 0x85 }, + { IMX296_REG_8BIT(0x375b), 0x00 }, + { IMX296_REG_8BIT(0x3832), 0xf5 }, + { IMX296_REG_8BIT(0x3833), 0x00 }, + { IMX296_REG_8BIT(0x38a2), 0xf6 }, + { IMX296_REG_8BIT(0x38a3), 0x00 }, + { IMX296_REG_8BIT(0x3a00), 0x80 }, + { IMX296_REG_8BIT(0x3d48), 0xa3 }, + { IMX296_REG_8BIT(0x3d49), 0x00 }, + { IMX296_REG_8BIT(0x3d4a), 0x85 }, + { IMX296_REG_8BIT(0x3d4b), 0x00 }, + { IMX296_REG_8BIT(0x400e), 0x58 }, + { IMX296_REG_8BIT(0x4014), 0x1c }, + { IMX296_REG_8BIT(0x4041), 0x2a }, + { IMX296_REG_8BIT(0x40a2), 0x06 }, + { IMX296_REG_8BIT(0x40c1), 0xf6 }, + { IMX296_REG_8BIT(0x40c7), 0x0f }, + { IMX296_REG_8BIT(0x40c8), 0x00 }, + { IMX296_REG_8BIT(0x4174), 0x00 }, +}; + +static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state) +{ + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + unsigned int i; + int ret = 0; + + format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + crop = v4l2_subdev_get_pad_crop(&sensor->subdev, state, 0); + + for (i = 0; i < ARRAY_SIZE(imx296_init_table); ++i) + imx296_write(sensor, imx296_init_table[i].reg, + imx296_init_table[i].value, &ret); + + if (crop->width != IMX296_PIXEL_ARRAY_WIDTH || + crop->height != IMX296_PIXEL_ARRAY_HEIGHT) { + imx296_write(sensor, IMX296_FID0_ROI, + IMX296_FID0_ROIH1ON | IMX296_FID0_ROIV1ON, &ret); + imx296_write(sensor, IMX296_FID0_ROIPH1, crop->left, &ret); + imx296_write(sensor, IMX296_FID0_ROIPV1, crop->top, &ret); + imx296_write(sensor, IMX296_FID0_ROIWH1, crop->width, &ret); + imx296_write(sensor, IMX296_FID0_ROIWV1, crop->height, &ret); + } else { + imx296_write(sensor, IMX296_FID0_ROI, 0, &ret); + } + + imx296_write(sensor, IMX296_CTRL0D, + (crop->width != format->width ? + IMX296_CTRL0D_HADD_ON_BINNING : 0) | + (crop->height != format->height ? + IMX296_CTRL0D_WINMODE_FD_BINNING : 0), + &ret); + + /* + * HMAX and VMAX configure horizontal and vertical blanking by + * specifying the total line time and frame time respectively. The line + * time is specified in operational clock units (which appears to be the + * output of an internal PLL, fixed at 74.25 MHz regardless of the + * exernal clock frequency), while the frame time is specified as a + * number of lines. + * + * In the vertical direction the sensor outputs the following: + * + * - one line for the FS packet + * - two lines of embedded data (DT 0x12) + * - six null lines (DT 0x10) + * - four lines of vertical effective optical black (DT 0x37) + * - 8 to 1088 lines of active image data (RAW10, DT 0x2b) + * - one line for the FE packet + * - 16 or more lines of vertical blanking + */ + imx296_write(sensor, IMX296_HMAX, 1100, &ret); + imx296_write(sensor, IMX296_VMAX, + format->height + sensor->vblank->cur.val, &ret); + + for (i = 0; i < ARRAY_SIZE(sensor->clk_params->incksel); ++i) + imx296_write(sensor, IMX296_INCKSEL(i), + sensor->clk_params->incksel[i], &ret); + imx296_write(sensor, IMX296_GTTABLENUM, 0xc5, &ret); + imx296_write(sensor, IMX296_CTRL418C, sensor->clk_params->ctrl418c, + &ret); + + imx296_write(sensor, IMX296_GAINDLY, IMX296_GAINDLY_NONE, &ret); + imx296_write(sensor, IMX296_BLKLEVEL, 0x03c, &ret); + + return ret; +} + +static int imx296_stream_on(struct imx296 *sensor) +{ + int ret = 0; + + imx296_write(sensor, IMX296_CTRL00, 0, &ret); + usleep_range(2000, 5000); + imx296_write(sensor, IMX296_CTRL0A, 0, &ret); + + return ret; +} + +static int imx296_stream_off(struct imx296 *sensor) +{ + int ret = 0; + + imx296_write(sensor, IMX296_CTRL0A, IMX296_CTRL0A_XMSTA, &ret); + imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, &ret); + + return ret; +} + +static int imx296_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx296 *sensor = to_imx296(sd); + struct v4l2_subdev_state *state; + int ret; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (!enable) { + ret = imx296_stream_off(sensor); + + pm_runtime_mark_last_busy(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + sensor->streaming = false; + + goto unlock; + } + + ret = pm_runtime_resume_and_get(sensor->dev); + if (ret < 0) + goto unlock; + + ret = imx296_setup(sensor, state); + if (ret < 0) + goto err_pm; + + /* + * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set + * the controls. The flag is reset to false further down if an error + * occurs. + */ + sensor->streaming = true; + + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); + if (ret < 0) + goto err_pm; + + ret = imx296_stream_on(sensor); + if (ret) + goto err_pm; + +unlock: + v4l2_subdev_unlock_state(state); + + return ret; + +err_pm: + /* + * In case of error, turn the power off synchronously as the device + * likely has no other chance to recover. + */ + pm_runtime_put_sync(sensor->dev); + sensor->streaming = false; + + goto unlock; +} + +static int imx296_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx296 *sensor = to_imx296(sd); + + if (code->index != 0) + return -EINVAL; + + code->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10 + : MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int imx296_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fse->pad); + + if (fse->index >= 2 || fse->code != format->code) + return -EINVAL; + + fse->min_width = IMX296_PIXEL_ARRAY_WIDTH / (fse->index + 1); + fse->max_width = fse->min_width; + fse->min_height = IMX296_PIXEL_ARRAY_HEIGHT / (fse->index + 1); + fse->max_height = fse->min_height; + + return 0; +} + +static int imx296_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + return 0; +} + +static int imx296_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct imx296 *sensor = to_imx296(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad); + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + /* + * Binning is only allowed when cropping is disabled according to the + * documentation. This should be double-checked. + */ + if (crop->width == IMX296_PIXEL_ARRAY_WIDTH && + crop->height == IMX296_PIXEL_ARRAY_HEIGHT) { + unsigned int width; + unsigned int height; + unsigned int hratio; + unsigned int vratio; + + /* Clamp the width and height to avoid dividing by zero. */ + width = clamp_t(unsigned int, fmt->format.width, + crop->width / 2, crop->width); + height = clamp_t(unsigned int, fmt->format.height, + crop->height / 2, crop->height); + + hratio = DIV_ROUND_CLOSEST(crop->width, width); + vratio = DIV_ROUND_CLOSEST(crop->height, height); + + format->width = crop->width / hratio; + format->height = crop->height / vratio; + } else { + format->width = crop->width; + format->height = crop->height; + } + + format->code = sensor->mono ? MEDIA_BUS_FMT_Y10_1X10 + : MEDIA_BUS_FMT_SBGGR10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + fmt->format = *format; + + return 0; +} + +static int imx296_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad); + break; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = IMX296_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX296_PIXEL_ARRAY_HEIGHT; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int imx296_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + struct v4l2_rect rect; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + /* + * Clamp the crop rectangle boundaries and align them to a multiple of 4 + * pixels to satisfy hardware requirements. + */ + rect.left = clamp(ALIGN(sel->r.left, 4), 0, + IMX296_PIXEL_ARRAY_WIDTH - IMX296_FID0_ROIWH1_MIN); + rect.top = clamp(ALIGN(sel->r.top, 4), 0, + IMX296_PIXEL_ARRAY_HEIGHT - IMX296_FID0_ROIWV1_MIN); + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), + IMX296_FID0_ROIWH1_MIN, IMX296_PIXEL_ARRAY_WIDTH); + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 4), + IMX296_FID0_ROIWV1_MIN, IMX296_PIXEL_ARRAY_HEIGHT); + + rect.width = min_t(unsigned int, rect.width, + IMX296_PIXEL_ARRAY_WIDTH - rect.left); + rect.height = min_t(unsigned int, rect.height, + IMX296_PIXEL_ARRAY_HEIGHT - rect.top); + + crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + + if (rect.width != crop->width || rect.height != crop->height) { + /* + * Reset the output image size if the crop rectangle size has + * been modified. + */ + format = v4l2_subdev_get_pad_format(sd, state, sel->pad); + format->width = rect.width; + format->height = rect.height; + } + + *crop = rect; + sel->r = rect; + + return 0; +} + +static int imx296_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_selection sel = { + .target = V4L2_SEL_TGT_CROP, + .r.width = IMX296_PIXEL_ARRAY_WIDTH, + .r.height = IMX296_PIXEL_ARRAY_HEIGHT, + }; + struct v4l2_subdev_format format = { + .format = { + .width = IMX296_PIXEL_ARRAY_WIDTH, + .height = IMX296_PIXEL_ARRAY_HEIGHT, + }, + }; + + imx296_set_selection(sd, state, &sel); + imx296_set_format(sd, state, &format); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx296_subdev_video_ops = { + .s_stream = imx296_s_stream, +}; + +static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = { + .enum_mbus_code = imx296_enum_mbus_code, + .enum_frame_size = imx296_enum_frame_size, + .get_fmt = imx296_get_format, + .set_fmt = imx296_set_format, + .get_selection = imx296_get_selection, + .set_selection = imx296_set_selection, + .init_cfg = imx296_init_cfg, +}; + +static const struct v4l2_subdev_ops imx296_subdev_ops = { + .video = &imx296_subdev_video_ops, + .pad = &imx296_subdev_pad_ops, +}; + +static int imx296_subdev_init(struct imx296 *sensor) +{ + struct i2c_client *client = to_i2c_client(sensor->dev); + int ret; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &imx296_subdev_ops); + + ret = imx296_ctrls_init(sensor); + if (ret < 0) + return ret; + + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); + if (ret < 0) { + v4l2_ctrl_handler_free(&sensor->ctrls); + return ret; + } + + sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock; + + v4l2_subdev_init_finalize(&sensor->subdev); + + return ret; +} + +static void imx296_subdev_cleanup(struct imx296 *sensor) +{ + media_entity_cleanup(&sensor->subdev.entity); + v4l2_ctrl_handler_free(&sensor->ctrls); +} + +/* ----------------------------------------------------------------------------- + * Power management + */ + +static int __maybe_unused imx296_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx296 *sensor = to_imx296(subdev); + + return imx296_power_on(sensor); +} + +static int __maybe_unused imx296_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx296 *sensor = to_imx296(subdev); + + imx296_power_off(sensor); + + return 0; +} + +static const struct dev_pm_ops imx296_pm_ops = { + SET_RUNTIME_PM_OPS(imx296_runtime_suspend, imx296_runtime_resume, NULL) +}; + +/* ----------------------------------------------------------------------------- + * Probe & Remove + */ + +static int imx296_read_temperature(struct imx296 *sensor, int *temp) +{ + int tmdout; + int ret; + + ret = imx296_write(sensor, IMX296_TMDCTRL, IMX296_TMDCTRL_LATCH, NULL); + if (ret < 0) + return ret; + + tmdout = imx296_read(sensor, IMX296_TMDOUT) & IMX296_TMDOUT_MASK; + if (tmdout < 0) + return tmdout; + + /* T(°C) = 246.312 - 0.304 * TMDOUT */; + *temp = 246312 - 304 * tmdout; + + return imx296_write(sensor, IMX296_TMDCTRL, 0, NULL); +} + +static int imx296_identify_model(struct imx296 *sensor) +{ + unsigned int model; + int temp = 0; + int ret; + + model = (uintptr_t)of_device_get_match_data(sensor->dev); + if (model) { + dev_dbg(sensor->dev, + "sensor model auto-detection disabled, forcing 0x%04x\n", + model); + sensor->mono = model & IMX296_SENSOR_INFO_MONO; + return 0; + } + + /* + * While most registers can be read when the sensor is in standby, this + * is not the case of the sensor info register :-( + */ + ret = imx296_write(sensor, IMX296_CTRL00, 0, NULL); + if (ret < 0) { + dev_err(sensor->dev, + "failed to get sensor out of standby (%d)\n", ret); + return ret; + } + + ret = imx296_read(sensor, IMX296_SENSOR_INFO); + if (ret < 0) { + dev_err(sensor->dev, "failed to read sensor information (%d)\n", + ret); + goto done; + } + + model = (ret >> 6) & 0x1ff; + + switch (model) { + case 296: + sensor->mono = ret & IMX296_SENSOR_INFO_MONO; + break; + /* + * The IMX297 seems to share features with the IMX296, it may be + * possible to support it in the same driver. + */ + case 297: + default: + dev_err(sensor->dev, "invalid device model 0x%04x\n", ret); + ret = -ENODEV; + goto done; + } + + ret = imx296_read_temperature(sensor, &temp); + if (ret < 0) + goto done; + + dev_info(sensor->dev, "found IMX%u%s (%u.%uC)\n", model, + sensor->mono ? "LL" : "LQ", temp / 1000, (temp / 100) % 10); + +done: + imx296_write(sensor, IMX296_CTRL00, IMX296_CTRL00_STANDBY, NULL); + return ret; +} + +static const struct regmap_config imx296_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + + .wr_table = &(const struct regmap_access_table) { + .no_ranges = (const struct regmap_range[]) { + { + .range_min = IMX296_SENSOR_INFO & 0xffff, + .range_max = (IMX296_SENSOR_INFO & 0xffff) + 1, + }, + }, + .n_no_ranges = 1, + }, +}; + +static int imx296_probe(struct i2c_client *client) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + unsigned long clk_rate; + struct imx296 *sensor; + unsigned int i; + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); + return -EIO; + } + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->dev = &client->dev; + + /* Acquire resources. */ + for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i) + sensor->supplies[i].supply = imx296_supply_names[i]; + + ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret) { + dev_err_probe(sensor->dev, ret, "failed to get supplies\n"); + return ret; + } + + sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), + "failed to get reset GPIO\n"); + + sensor->clk = devm_clk_get(sensor->dev, "inck"); + if (IS_ERR(sensor->clk)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), + "failed to get clock\n"); + + clk_rate = clk_get_rate(sensor->clk); + for (i = 0; i < ARRAY_SIZE(imx296_clk_params); ++i) { + if (clk_rate == imx296_clk_params[i].freq) { + sensor->clk_params = &imx296_clk_params[i]; + break; + } + } + + if (!sensor->clk_params) { + dev_err(sensor->dev, "unsupported clock rate %lu\n", clk_rate); + return -EINVAL; + } + + sensor->regmap = devm_regmap_init_i2c(client, &imx296_regmap_config); + if (IS_ERR(sensor->regmap)) + return PTR_ERR(sensor->regmap); + + /* + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here, identify it, and fully initialize it. + */ + ret = imx296_power_on(sensor); + if (ret < 0) + return ret; + + ret = imx296_identify_model(sensor); + if (ret < 0) + goto err_power; + + /* Initialize the V4L2 subdev. */ + ret = imx296_subdev_init(sensor); + if (ret < 0) + goto err_power; + + /* + * Enable runtime PM. As the device has been powered manually, mark it + * as active, and increase the usage count without resuming the device. + */ + pm_runtime_set_active(sensor->dev); + pm_runtime_get_noresume(sensor->dev); + pm_runtime_enable(sensor->dev); + + /* Register the V4L2 subdev. */ + ret = v4l2_async_register_subdev(&sensor->subdev); + if (ret < 0) + goto err_pm; + + /* + * Finally, enable autosuspend and decrease the usage count. The device + * will get suspended after the autosuspend delay, turning the power + * off. + */ + pm_runtime_set_autosuspend_delay(sensor->dev, 1000); + pm_runtime_use_autosuspend(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + return 0; + +err_pm: + pm_runtime_disable(sensor->dev); + pm_runtime_put_noidle(sensor->dev); + imx296_subdev_cleanup(sensor); +err_power: + imx296_power_off(sensor); + return ret; +} + +static void imx296_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx296 *sensor = to_imx296(subdev); + + v4l2_async_unregister_subdev(subdev); + + imx296_subdev_cleanup(sensor); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(sensor->dev); + if (!pm_runtime_status_suspended(sensor->dev)) + imx296_power_off(sensor); + pm_runtime_set_suspended(sensor->dev); +} + +static const struct of_device_id imx296_of_match[] = { + { .compatible = "sony,imx296", .data = NULL }, + { .compatible = "sony,imx296ll", .data = (void *)IMX296_SENSOR_INFO_IMX296LL }, + { .compatible = "sony,imx296lq", .data = (void *)IMX296_SENSOR_INFO_IMX296LQ }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx296_of_match); + +static struct i2c_driver imx296_i2c_driver = { + .driver = { + .of_match_table = imx296_of_match, + .name = "imx296", + .pm = &imx296_pm_ops + }, + .probe_new = imx296_probe, + .remove = imx296_remove, +}; + +module_i2c_driver(imx296_i2c_driver); + +MODULE_DESCRIPTION("Sony IMX296 Camera driver"); +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c new file mode 100644 index 000000000000..d90392df98c7 --- /dev/null +++ b/drivers/media/i2c/imx415.c @@ -0,0 +1,1300 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the Sony IMX415 CMOS Image Sensor. + * + * Copyright (C) 2023 WolfVision GmbH. + */ + +#include <linux/clk.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/videodev2.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +#define IMX415_PIXEL_ARRAY_TOP 0 +#define IMX415_PIXEL_ARRAY_LEFT 0 +#define IMX415_PIXEL_ARRAY_WIDTH 3864 +#define IMX415_PIXEL_ARRAY_HEIGHT 2192 +#define IMX415_PIXEL_ARRAY_VBLANK 58 + +#define IMX415_NUM_CLK_PARAM_REGS 11 + +#define IMX415_REG_8BIT(n) ((1 << 16) | (n)) +#define IMX415_REG_16BIT(n) ((2 << 16) | (n)) +#define IMX415_REG_24BIT(n) ((3 << 16) | (n)) +#define IMX415_REG_SIZE_SHIFT 16 +#define IMX415_REG_ADDR_MASK 0xffff + +#define IMX415_MODE IMX415_REG_8BIT(0x3000) +#define IMX415_MODE_OPERATING (0) +#define IMX415_MODE_STANDBY BIT(0) +#define IMX415_REGHOLD IMX415_REG_8BIT(0x3001) +#define IMX415_REGHOLD_INVALID (0) +#define IMX415_REGHOLD_VALID BIT(0) +#define IMX415_XMSTA IMX415_REG_8BIT(0x3002) +#define IMX415_XMSTA_START (0) +#define IMX415_XMSTA_STOP BIT(0) +#define IMX415_BCWAIT_TIME IMX415_REG_16BIT(0x3008) +#define IMX415_CPWAIT_TIME IMX415_REG_16BIT(0x300A) +#define IMX415_WINMODE IMX415_REG_8BIT(0x301C) +#define IMX415_ADDMODE IMX415_REG_8BIT(0x3022) +#define IMX415_REVERSE IMX415_REG_8BIT(0x3030) +#define IMX415_HREVERSE_SHIFT (0) +#define IMX415_VREVERSE_SHIFT BIT(0) +#define IMX415_ADBIT IMX415_REG_8BIT(0x3031) +#define IMX415_MDBIT IMX415_REG_8BIT(0x3032) +#define IMX415_SYS_MODE IMX415_REG_8BIT(0x3033) +#define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0) +#define IMX415_DRV IMX415_REG_8BIT(0x30C1) +#define IMX415_VMAX IMX415_REG_24BIT(0x3024) +#define IMX415_HMAX IMX415_REG_16BIT(0x3028) +#define IMX415_SHR0 IMX415_REG_24BIT(0x3050) +#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090) +#define IMX415_AGAIN_MIN 0 +#define IMX415_AGAIN_MAX 100 +#define IMX415_AGAIN_STEP 1 +#define IMX415_BLKLEVEL IMX415_REG_16BIT(0x30E2) +#define IMX415_BLKLEVEL_DEFAULT 50 +#define IMX415_TPG_EN_DUOUT IMX415_REG_8BIT(0x30E4) +#define IMX415_TPG_PATSEL_DUOUT IMX415_REG_8BIT(0x30E6) +#define IMX415_TPG_COLORWIDTH IMX415_REG_8BIT(0x30E8) +#define IMX415_TESTCLKEN_MIPI IMX415_REG_8BIT(0x3110) +#define IMX415_INCKSEL1 IMX415_REG_8BIT(0x3115) +#define IMX415_INCKSEL2 IMX415_REG_8BIT(0x3116) +#define IMX415_INCKSEL3 IMX415_REG_16BIT(0x3118) +#define IMX415_INCKSEL4 IMX415_REG_16BIT(0x311A) +#define IMX415_INCKSEL5 IMX415_REG_8BIT(0x311E) +#define IMX415_DIG_CLP_MODE IMX415_REG_8BIT(0x32C8) +#define IMX415_WRJ_OPEN IMX415_REG_8BIT(0x3390) +#define IMX415_SENSOR_INFO IMX415_REG_16BIT(0x3F12) +#define IMX415_SENSOR_INFO_MASK 0xFFF +#define IMX415_CHIP_ID 0x514 +#define IMX415_LANEMODE IMX415_REG_16BIT(0x4001) +#define IMX415_LANEMODE_2 1 +#define IMX415_LANEMODE_4 3 +#define IMX415_TXCLKESC_FREQ IMX415_REG_16BIT(0x4004) +#define IMX415_INCKSEL6 IMX415_REG_8BIT(0x400C) +#define IMX415_TCLKPOST IMX415_REG_16BIT(0x4018) +#define IMX415_TCLKPREPARE IMX415_REG_16BIT(0x401A) +#define IMX415_TCLKTRAIL IMX415_REG_16BIT(0x401C) +#define IMX415_TCLKZERO IMX415_REG_16BIT(0x401E) +#define IMX415_THSPREPARE IMX415_REG_16BIT(0x4020) +#define IMX415_THSZERO IMX415_REG_16BIT(0x4022) +#define IMX415_THSTRAIL IMX415_REG_16BIT(0x4024) +#define IMX415_THSEXIT IMX415_REG_16BIT(0x4026) +#define IMX415_TLPX IMX415_REG_16BIT(0x4028) +#define IMX415_INCKSEL7 IMX415_REG_8BIT(0x4074) + +struct imx415_reg { + u32 address; + u32 val; +}; + +static const char *const imx415_supply_names[] = { + "dvdd", + "ovdd", + "avdd", +}; + +/* + * The IMX415 data sheet uses lane rates but v4l2 uses link frequency to + * describe MIPI CSI-2 speed. This driver uses lane rates wherever possible + * and converts them to link frequencies by a factor of two when needed. + */ +static const s64 link_freq_menu_items[] = { + 594000000 / 2, 720000000 / 2, 891000000 / 2, + 1440000000 / 2, 1485000000 / 2, +}; + +struct imx415_clk_params { + u64 lane_rate; + u64 inck; + struct imx415_reg regs[IMX415_NUM_CLK_PARAM_REGS]; +}; + +/* INCK Settings - includes all lane rate and INCK dependent registers */ +static const struct imx415_clk_params imx415_clk_params[] = { + { + .lane_rate = 594000000, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x7 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x084 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 720000000, + .inck = 24000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, + .regs[2] = { IMX415_SYS_MODE, 0x9 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0B4 }, + .regs[6] = { IMX415_INCKSEL4, 0x0FC }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, + }, + { + .lane_rate = 891000000, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x5 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0C6 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x0 }, + .regs[9] = { IMX415_INCKSEL7, 0x1 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, + { + .lane_rate = 1440000000, + .inck = 24000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x054 }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x03B }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0B4 }, + .regs[6] = { IMX415_INCKSEL4, 0x0FC }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 }, + }, + { + .lane_rate = 1485000000, + .inck = 27000000, + .regs[0] = { IMX415_BCWAIT_TIME, 0x05D }, + .regs[1] = { IMX415_CPWAIT_TIME, 0x042 }, + .regs[2] = { IMX415_SYS_MODE, 0x8 }, + .regs[3] = { IMX415_INCKSEL1, 0x00 }, + .regs[4] = { IMX415_INCKSEL2, 0x23 }, + .regs[5] = { IMX415_INCKSEL3, 0x0A5 }, + .regs[6] = { IMX415_INCKSEL4, 0x0E7 }, + .regs[7] = { IMX415_INCKSEL5, 0x23 }, + .regs[8] = { IMX415_INCKSEL6, 0x1 }, + .regs[9] = { IMX415_INCKSEL7, 0x0 }, + .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 }, + }, +}; + +/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */ +static const struct imx415_reg imx415_mode_2_720[] = { + { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x07F0 }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x006F }, + { IMX415_TCLKPREPARE, 0x002F }, + { IMX415_TCLKTRAIL, 0x002F }, + { IMX415_TCLKZERO, 0x00BF }, + { IMX415_THSPREPARE, 0x002F }, + { IMX415_THSZERO, 0x0057 }, + { IMX415_THSTRAIL, 0x002F }, + { IMX415_THSEXIT, 0x004F }, + { IMX415_TLPX, 0x0027 }, +}; + +/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */ +static const struct imx415_reg imx415_mode_2_1440[] = { + { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x042A }, + { IMX415_LANEMODE, IMX415_LANEMODE_2 }, + { IMX415_TCLKPOST, 0x009F }, + { IMX415_TCLKPREPARE, 0x0057 }, + { IMX415_TCLKTRAIL, 0x0057 }, + { IMX415_TCLKZERO, 0x0187 }, + { IMX415_THSPREPARE, 0x005F }, + { IMX415_THSZERO, 0x00A7 }, + { IMX415_THSTRAIL, 0x005F }, + { IMX415_THSEXIT, 0x0097 }, + { IMX415_TLPX, 0x004F }, +}; + +/* all-pixel 4-lane 891 Mbps 30 Hz mode */ +static const struct imx415_reg imx415_mode_4_891[] = { + { IMX415_VMAX, 0x08CA }, + { IMX415_HMAX, 0x044C }, + { IMX415_LANEMODE, IMX415_LANEMODE_4 }, + { IMX415_TCLKPOST, 0x007F }, + { IMX415_TCLKPREPARE, 0x0037 }, + { IMX415_TCLKTRAIL, 0x0037 }, + { IMX415_TCLKZERO, 0x00F7 }, + { IMX415_THSPREPARE, 0x003F }, + { IMX415_THSZERO, 0x006F }, + { IMX415_THSTRAIL, 0x003F }, + { IMX415_THSEXIT, 0x005F }, + { IMX415_TLPX, 0x002F }, +}; + +struct imx415_mode_reg_list { + u32 num_of_regs; + const struct imx415_reg *regs; +}; + +/* + * Mode : number of lanes, lane rate and frame rate dependent settings + * + * pixel_rate and hmax_pix are needed to calculate hblank for the v4l2 ctrl + * interface. These values can not be found in the data sheet and should be + * treated as virtual values. Use following table when adding new modes. + * + * lane_rate lanes fps hmax_pix pixel_rate + * + * 594 2 10.000 4400 99000000 + * 891 2 15.000 4400 148500000 + * 720 2 15.748 4064 144000000 + * 1782 2 30.000 4400 297000000 + * 2079 2 30.000 4400 297000000 + * 1440 2 30.019 4510 304615385 + * + * 594 4 20.000 5500 247500000 + * 594 4 25.000 4400 247500000 + * 720 4 25.000 4400 247500000 + * 720 4 30.019 4510 304615385 + * 891 4 30.000 4400 297000000 + * 1440 4 30.019 4510 304615385 + * 1440 4 60.038 4510 609230769 + * 1485 4 60.000 4400 594000000 + * 1782 4 60.000 4400 594000000 + * 2079 4 60.000 4400 594000000 + * 2376 4 90.164 4392 891000000 + */ +struct imx415_mode { + u64 lane_rate; + u32 lanes; + u32 hmax_pix; + u64 pixel_rate; + struct imx415_mode_reg_list reg_list; +}; + +/* mode configs */ +static const struct imx415_mode supported_modes[] = { + { + .lane_rate = 720000000, + .lanes = 2, + .hmax_pix = 4064, + .pixel_rate = 144000000, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_2_720), + .regs = imx415_mode_2_720, + }, + }, + { + .lane_rate = 1440000000, + .lanes = 2, + .hmax_pix = 4510, + .pixel_rate = 304615385, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440), + .regs = imx415_mode_2_1440, + }, + }, + { + .lane_rate = 891000000, + .lanes = 4, + .hmax_pix = 4400, + .pixel_rate = 297000000, + .reg_list = { + .num_of_regs = ARRAY_SIZE(imx415_mode_4_891), + .regs = imx415_mode_4_891, + }, + }, +}; + +static const struct regmap_config imx415_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const char *const imx415_test_pattern_menu[] = { + "disabled", + "solid black", + "solid white", + "solid dark gray", + "solid light gray", + "stripes light/dark grey", + "stripes dark/light grey", + "stripes black/dark grey", + "stripes dark grey/black", + "stripes black/white", + "stripes white/black", + "horizontal color bar", + "vertical color bar", +}; + +struct imx415 { + struct device *dev; + struct clk *clk; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx415_supply_names)]; + struct gpio_desc *reset; + struct regmap *regmap; + + const struct imx415_clk_params *clk_params; + + bool streaming; + + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + + unsigned int cur_mode; + unsigned int num_data_lanes; +}; + +/* + * This table includes fixed register settings and a bunch of undocumented + * registers that have to be set to another value than default. + */ +static const struct imx415_reg imx415_init_table[] = { + /* use all-pixel readout mode, no flip */ + { IMX415_WINMODE, 0x00 }, + { IMX415_ADDMODE, 0x00 }, + { IMX415_REVERSE, 0x00 }, + /* use RAW 10-bit mode */ + { IMX415_ADBIT, 0x00 }, + { IMX415_MDBIT, 0x00 }, + /* output VSYNC on XVS and low on XHS */ + { IMX415_OUTSEL, 0x22 }, + { IMX415_DRV, 0x00 }, + + /* SONY magic registers */ + { IMX415_REG_8BIT(0x32D4), 0x21 }, + { IMX415_REG_8BIT(0x32EC), 0xA1 }, + { IMX415_REG_8BIT(0x3452), 0x7F }, + { IMX415_REG_8BIT(0x3453), 0x03 }, + { IMX415_REG_8BIT(0x358A), 0x04 }, + { IMX415_REG_8BIT(0x35A1), 0x02 }, + { IMX415_REG_8BIT(0x36BC), 0x0C }, + { IMX415_REG_8BIT(0x36CC), 0x53 }, + { IMX415_REG_8BIT(0x36CD), 0x00 }, + { IMX415_REG_8BIT(0x36CE), 0x3C }, + { IMX415_REG_8BIT(0x36D0), 0x8C }, + { IMX415_REG_8BIT(0x36D1), 0x00 }, + { IMX415_REG_8BIT(0x36D2), 0x71 }, + { IMX415_REG_8BIT(0x36D4), 0x3C }, + { IMX415_REG_8BIT(0x36D6), 0x53 }, + { IMX415_REG_8BIT(0x36D7), 0x00 }, + { IMX415_REG_8BIT(0x36D8), 0x71 }, + { IMX415_REG_8BIT(0x36DA), 0x8C }, + { IMX415_REG_8BIT(0x36DB), 0x00 }, + { IMX415_REG_8BIT(0x3724), 0x02 }, + { IMX415_REG_8BIT(0x3726), 0x02 }, + { IMX415_REG_8BIT(0x3732), 0x02 }, + { IMX415_REG_8BIT(0x3734), 0x03 }, + { IMX415_REG_8BIT(0x3736), 0x03 }, + { IMX415_REG_8BIT(0x3742), 0x03 }, + { IMX415_REG_8BIT(0x3862), 0xE0 }, + { IMX415_REG_8BIT(0x38CC), 0x30 }, + { IMX415_REG_8BIT(0x38CD), 0x2F }, + { IMX415_REG_8BIT(0x395C), 0x0C }, + { IMX415_REG_8BIT(0x3A42), 0xD1 }, + { IMX415_REG_8BIT(0x3A4C), 0x77 }, + { IMX415_REG_8BIT(0x3AE0), 0x02 }, + { IMX415_REG_8BIT(0x3AEC), 0x0C }, + { IMX415_REG_8BIT(0x3B00), 0x2E }, + { IMX415_REG_8BIT(0x3B06), 0x29 }, + { IMX415_REG_8BIT(0x3B98), 0x25 }, + { IMX415_REG_8BIT(0x3B99), 0x21 }, + { IMX415_REG_8BIT(0x3B9B), 0x13 }, + { IMX415_REG_8BIT(0x3B9C), 0x13 }, + { IMX415_REG_8BIT(0x3B9D), 0x13 }, + { IMX415_REG_8BIT(0x3B9E), 0x13 }, + { IMX415_REG_8BIT(0x3BA1), 0x00 }, + { IMX415_REG_8BIT(0x3BA2), 0x06 }, + { IMX415_REG_8BIT(0x3BA3), 0x0B }, + { IMX415_REG_8BIT(0x3BA4), 0x10 }, + { IMX415_REG_8BIT(0x3BA5), 0x14 }, + { IMX415_REG_8BIT(0x3BA6), 0x18 }, + { IMX415_REG_8BIT(0x3BA7), 0x1A }, + { IMX415_REG_8BIT(0x3BA8), 0x1A }, + { IMX415_REG_8BIT(0x3BA9), 0x1A }, + { IMX415_REG_8BIT(0x3BAC), 0xED }, + { IMX415_REG_8BIT(0x3BAD), 0x01 }, + { IMX415_REG_8BIT(0x3BAE), 0xF6 }, + { IMX415_REG_8BIT(0x3BAF), 0x02 }, + { IMX415_REG_8BIT(0x3BB0), 0xA2 }, + { IMX415_REG_8BIT(0x3BB1), 0x03 }, + { IMX415_REG_8BIT(0x3BB2), 0xE0 }, + { IMX415_REG_8BIT(0x3BB3), 0x03 }, + { IMX415_REG_8BIT(0x3BB4), 0xE0 }, + { IMX415_REG_8BIT(0x3BB5), 0x03 }, + { IMX415_REG_8BIT(0x3BB6), 0xE0 }, + { IMX415_REG_8BIT(0x3BB7), 0x03 }, + { IMX415_REG_8BIT(0x3BB8), 0xE0 }, + { IMX415_REG_8BIT(0x3BBA), 0xE0 }, + { IMX415_REG_8BIT(0x3BBC), 0xDA }, + { IMX415_REG_8BIT(0x3BBE), 0x88 }, + { IMX415_REG_8BIT(0x3BC0), 0x44 }, + { IMX415_REG_8BIT(0x3BC2), 0x7B }, + { IMX415_REG_8BIT(0x3BC4), 0xA2 }, + { IMX415_REG_8BIT(0x3BC8), 0xBD }, + { IMX415_REG_8BIT(0x3BCA), 0xBD }, +}; + +static inline struct imx415 *to_imx415(struct v4l2_subdev *sd) +{ + return container_of(sd, struct imx415, subdev); +} + +static int imx415_read(struct imx415 *sensor, u32 addr) +{ + u8 data[3] = { 0 }; + int ret; + + ret = regmap_raw_read(sensor->regmap, addr & IMX415_REG_ADDR_MASK, data, + (addr >> IMX415_REG_SIZE_SHIFT) & 3); + if (ret < 0) + return ret; + + return (data[2] << 16) | (data[1] << 8) | data[0]; +} + +static int imx415_write(struct imx415 *sensor, u32 addr, u32 value) +{ + u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 }; + int ret; + + ret = regmap_raw_write(sensor->regmap, addr & IMX415_REG_ADDR_MASK, + data, (addr >> IMX415_REG_SIZE_SHIFT) & 3); + if (ret < 0) + dev_err_ratelimited(sensor->dev, + "%u-bit write to 0x%04x failed: %d\n", + ((addr >> IMX415_REG_SIZE_SHIFT) & 3) * 8, + addr & IMX415_REG_ADDR_MASK, ret); + + return 0; +} + +static int imx415_set_testpattern(struct imx415 *sensor, int val) +{ + int ret; + + if (val) { + ret = imx415_write(sensor, IMX415_BLKLEVEL, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x01); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_PATSEL_DUOUT, val - 1); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_COLORWIDTH, 0x01); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x20); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x00); + } else { + ret = imx415_write(sensor, IMX415_BLKLEVEL, + IMX415_BLKLEVEL_DEFAULT); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TPG_EN_DUOUT, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_TESTCLKEN_MIPI, 0x00); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_DIG_CLP_MODE, 0x01); + if (ret) + return ret; + ret = imx415_write(sensor, IMX415_WRJ_OPEN, 0x01); + } + return 0; +} + +static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx415 *sensor = container_of(ctrl->handler, struct imx415, + ctrls); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + unsigned int vmax; + unsigned int flip; + + if (!sensor->streaming) + return 0; + + state = v4l2_subdev_get_locked_active_state(&sensor->subdev); + format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* clamp the exposure value to VMAX. */ + vmax = format->height + sensor->vblank->cur.val; + ctrl->val = min_t(int, ctrl->val, vmax); + return imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + + case V4L2_CID_ANALOGUE_GAIN: + /* analogue gain in 0.3 dB step size */ + return imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) | + (sensor->vflip->val << IMX415_VREVERSE_SHIFT); + return imx415_write(sensor, IMX415_REVERSE, flip); + + case V4L2_CID_TEST_PATTERN: + return imx415_set_testpattern(sensor, ctrl->val); + + default: + return -EINVAL; + } +} + +static const struct v4l2_ctrl_ops imx415_ctrl_ops = { + .s_ctrl = imx415_s_ctrl, +}; + +static int imx415_ctrls_init(struct imx415 *sensor) +{ + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl *ctrl; + u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate; + u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate; + u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT + + IMX415_PIXEL_ARRAY_VBLANK - 8; + u32 hblank; + unsigned int i; + int ret; + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret < 0) + return ret; + + v4l2_ctrl_handler_init(&sensor->ctrls, 10); + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); ++i) { + if (lane_rate == link_freq_menu_items[i] * 2) + break; + } + if (i == ARRAY_SIZE(link_freq_menu_items)) { + return dev_err_probe(sensor->dev, -EINVAL, + "lane rate %llu not supported\n", + lane_rate); + } + + ctrl = v4l2_ctrl_new_int_menu(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, i, + link_freq_menu_items); + + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_EXPOSURE, + 4, exposure_max, 1, exposure_max); + + v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, IMX415_AGAIN_MIN, + IMX415_AGAIN_MAX, IMX415_AGAIN_STEP, + IMX415_AGAIN_MIN); + + hblank = supported_modes[sensor->cur_mode].hmax_pix - + IMX415_PIXEL_ARRAY_WIDTH; + ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, 1, hblank); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_VBLANK, + IMX415_PIXEL_ARRAY_VBLANK, + IMX415_PIXEL_ARRAY_VBLANK, 1, + IMX415_PIXEL_ARRAY_VBLANK); + if (sensor->vblank) + sensor->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* + * The pixel rate used here is a virtual value and can be used for + * calculating the frame rate together with hblank. It may not + * necessarily be the physically correct pixel clock. + */ + v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate, + pixel_rate, 1, pixel_rate); + + sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &imx415_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx415_test_pattern_menu) - 1, + 0, 0, imx415_test_pattern_menu); + + v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &imx415_ctrl_ops, + &props); + + if (sensor->ctrls.error) { + dev_err_probe(sensor->dev, sensor->ctrls.error, + "failed to add controls\n"); + v4l2_ctrl_handler_free(&sensor->ctrls); + return sensor->ctrls.error; + } + sensor->subdev.ctrl_handler = &sensor->ctrls; + + return 0; +} + +static int imx415_set_mode(struct imx415 *sensor, int mode) +{ + const struct imx415_reg *reg; + unsigned int i; + int ret = 0; + + if (mode >= ARRAY_SIZE(supported_modes)) { + dev_err(sensor->dev, "Mode %d not supported\n", mode); + return -EINVAL; + } + + for (i = 0; i < supported_modes[mode].reg_list.num_of_regs; ++i) { + reg = &supported_modes[mode].reg_list.regs[i]; + ret = imx415_write(sensor, reg->address, reg->val); + if (ret) + return ret; + } + + for (i = 0; i < IMX415_NUM_CLK_PARAM_REGS; ++i) { + reg = &sensor->clk_params->regs[i]; + ret = imx415_write(sensor, reg->address, reg->val); + if (ret) + return ret; + } + + return 0; +} + +static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state) +{ + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(imx415_init_table); ++i) { + ret = imx415_write(sensor, imx415_init_table[i].address, + imx415_init_table[i].val); + if (ret) + return ret; + } + + return imx415_set_mode(sensor, sensor->cur_mode); +} + +static int imx415_wakeup(struct imx415 *sensor) +{ + int ret; + + ret = imx415_write(sensor, IMX415_MODE, IMX415_MODE_OPERATING); + if (ret) + return ret; + + /* + * According to the datasheet we have to wait at least 63 us after + * leaving standby mode. But this doesn't work even after 30 ms. + * So probably this should be 63 ms and therefore we wait for 80 ms. + */ + msleep(80); + + return 0; +} + +static int imx415_stream_on(struct imx415 *sensor) +{ + int ret; + + ret = imx415_wakeup(sensor); + if (ret) + return ret; + + return imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_START); +} + +static int imx415_stream_off(struct imx415 *sensor) +{ + int ret; + + ret = imx415_write(sensor, IMX415_XMSTA, IMX415_XMSTA_STOP); + if (ret) + return ret; + + return imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); +} + +static int imx415_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx415 *sensor = to_imx415(sd); + struct v4l2_subdev_state *state; + int ret; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (!enable) { + ret = imx415_stream_off(sensor); + + pm_runtime_mark_last_busy(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + sensor->streaming = false; + + goto unlock; + } + + ret = pm_runtime_resume_and_get(sensor->dev); + if (ret < 0) + goto unlock; + + ret = imx415_setup(sensor, state); + if (ret) + goto err_pm; + + /* + * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set + * the controls. The flag is reset to false further down if an error + * occurs. + */ + sensor->streaming = true; + + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); + if (ret < 0) + goto err_pm; + + ret = imx415_stream_on(sensor); + if (ret) + goto err_pm; + + ret = 0; + +unlock: + v4l2_subdev_unlock_state(state); + + return ret; + +err_pm: + /* + * In case of error, turn the power off synchronously as the device + * likely has no other chance to recover. + */ + pm_runtime_put_sync(sensor->dev); + sensor->streaming = false; + + goto unlock; +} + +static int imx415_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGBRG10_1X10; + + return 0; +} + +static int imx415_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fse->pad); + + if (fse->index > 0 || fse->code != format->code) + return -EINVAL; + + fse->min_width = IMX415_PIXEL_ARRAY_WIDTH; + fse->max_width = fse->min_width; + fse->min_height = IMX415_PIXEL_ARRAY_HEIGHT; + fse->max_height = fse->min_height; + return 0; +} + +static int imx415_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + return 0; +} + +static int imx415_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + format->width = fmt->format.width; + format->height = fmt->format.height; + format->code = MEDIA_BUS_FMT_SGBRG10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_DEFAULT; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + fmt->format = *format; + return 0; +} + +static int imx415_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = IMX415_PIXEL_ARRAY_TOP; + sel->r.left = IMX415_PIXEL_ARRAY_LEFT; + sel->r.width = IMX415_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX415_PIXEL_ARRAY_HEIGHT; + + return 0; + } + + return -EINVAL; +} + +static int imx415_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format format = { + .format = { + .width = IMX415_PIXEL_ARRAY_WIDTH, + .height = IMX415_PIXEL_ARRAY_HEIGHT, + }, + }; + + imx415_set_format(sd, state, &format); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx415_subdev_video_ops = { + .s_stream = imx415_s_stream, +}; + +static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = { + .enum_mbus_code = imx415_enum_mbus_code, + .enum_frame_size = imx415_enum_frame_size, + .get_fmt = imx415_get_format, + .set_fmt = imx415_set_format, + .get_selection = imx415_get_selection, + .init_cfg = imx415_init_cfg, +}; + +static const struct v4l2_subdev_ops imx415_subdev_ops = { + .video = &imx415_subdev_video_ops, + .pad = &imx415_subdev_pad_ops, +}; + +static int imx415_subdev_init(struct imx415 *sensor) +{ + struct i2c_client *client = to_i2c_client(sensor->dev); + int ret; + + v4l2_i2c_subdev_init(&sensor->subdev, client, &imx415_subdev_ops); + + ret = imx415_ctrls_init(sensor); + if (ret) + return ret; + + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); + if (ret < 0) { + v4l2_ctrl_handler_free(&sensor->ctrls); + return ret; + } + + sensor->subdev.state_lock = sensor->subdev.ctrl_handler->lock; + v4l2_subdev_init_finalize(&sensor->subdev); + + return 0; +} + +static void imx415_subdev_cleanup(struct imx415 *sensor) +{ + media_entity_cleanup(&sensor->subdev.entity); + v4l2_ctrl_handler_free(&sensor->ctrls); +} + +static int imx415_power_on(struct imx415 *sensor) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) + return ret; + + gpiod_set_value_cansleep(sensor->reset, 0); + + udelay(1); + + ret = clk_prepare_enable(sensor->clk); + if (ret < 0) + goto err_reset; + + /* + * Data sheet states that 20 us are required before communication start, + * but this doesn't work in all cases. Use 100 us to be on the safe + * side. + */ + usleep_range(100, 200); + + return 0; + +err_reset: + gpiod_set_value_cansleep(sensor->reset, 1); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); + return ret; +} + +static void imx415_power_off(struct imx415 *sensor) +{ + clk_disable_unprepare(sensor->clk); + gpiod_set_value_cansleep(sensor->reset, 1); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); +} + +static int imx415_identify_model(struct imx415 *sensor) +{ + int model, ret; + + /* + * While most registers can be read when the sensor is in standby, this + * is not the case of the sensor info register :-( + */ + ret = imx415_wakeup(sensor); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to get sensor out of standby\n"); + + ret = imx415_read(sensor, IMX415_SENSOR_INFO); + if (ret < 0) { + dev_err_probe(sensor->dev, ret, + "failed to read sensor information\n"); + goto done; + } + + model = ret & IMX415_SENSOR_INFO_MASK; + + switch (model) { + case IMX415_CHIP_ID: + dev_info(sensor->dev, "Detected IMX415 image sensor\n"); + break; + default: + ret = dev_err_probe(sensor->dev, -ENODEV, + "invalid device model 0x%04x\n", model); + goto done; + } + + ret = 0; + +done: + imx415_write(sensor, IMX415_MODE, IMX415_MODE_STANDBY); + return ret; +} + +static int imx415_check_inck(unsigned long inck, u64 link_frequency) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) { + if ((imx415_clk_params[i].lane_rate == link_frequency * 2) && + imx415_clk_params[i].inck == inck) + break; + } + + if (i == ARRAY_SIZE(imx415_clk_params)) + return -EINVAL; + else + return 0; +} + +static int imx415_parse_hw_config(struct imx415 *sensor) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep; + u64 lane_rate; + unsigned long inck; + unsigned int i, j; + int ret; + + for (i = 0; i < ARRAY_SIZE(sensor->supplies); ++i) + sensor->supplies[i].supply = imx415_supply_names[i]; + + ret = devm_regulator_bulk_get(sensor->dev, ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to get supplies\n"); + + sensor->reset = devm_gpiod_get_optional(sensor->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), + "failed to get reset GPIO\n"); + + sensor->clk = devm_clk_get(sensor->dev, "inck"); + if (IS_ERR(sensor->clk)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), + "failed to get clock\n"); + + ep = fwnode_graph_get_next_endpoint(dev_fwnode(sensor->dev), NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + switch (bus_cfg.bus.mipi_csi2.num_data_lanes) { + case 2: + case 4: + sensor->num_data_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + break; + default: + ret = dev_err_probe(sensor->dev, -EINVAL, + "invalid number of CSI2 data lanes %d\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "no link frequencies defined"); + goto done_endpoint_free; + } + + /* + * Check if there exists a sensor mode defined for current INCK, + * number of lanes and given lane rates. + */ + inck = clk_get_rate(sensor->clk); + for (i = 0; i < bus_cfg.nr_of_link_frequencies; ++i) { + if (imx415_check_inck(inck, bus_cfg.link_frequencies[i])) { + dev_dbg(sensor->dev, + "INCK %lu Hz not supported for this link freq", + inck); + continue; + } + + for (j = 0; j < ARRAY_SIZE(supported_modes); ++j) { + if (sensor->num_data_lanes != supported_modes[j].lanes) + continue; + if (bus_cfg.link_frequencies[i] * 2 != + supported_modes[j].lane_rate) + continue; + sensor->cur_mode = j; + break; + } + if (j < ARRAY_SIZE(supported_modes)) + break; + } + if (i == bus_cfg.nr_of_link_frequencies) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "no valid sensor mode defined\n"); + goto done_endpoint_free; + } + + lane_rate = supported_modes[sensor->cur_mode].lane_rate; + for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) { + if (lane_rate == imx415_clk_params[i].lane_rate && + inck == imx415_clk_params[i].inck) { + sensor->clk_params = &imx415_clk_params[i]; + break; + } + } + if (i == ARRAY_SIZE(imx415_clk_params)) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "Mode %d not supported\n", + sensor->cur_mode); + goto done_endpoint_free; + } + + ret = 0; + dev_dbg(sensor->dev, "clock: %lu Hz, lane_rate: %llu bps, lanes: %d\n", + inck, lane_rate, sensor->num_data_lanes); + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int imx415_probe(struct i2c_client *client) +{ + struct imx415 *sensor; + int ret; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->dev = &client->dev; + + ret = imx415_parse_hw_config(sensor); + if (ret) + return ret; + + sensor->regmap = devm_regmap_init_i2c(client, &imx415_regmap_config); + if (IS_ERR(sensor->regmap)) + return PTR_ERR(sensor->regmap); + + /* + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here, identify it, and fully initialize it. + */ + ret = imx415_power_on(sensor); + if (ret) + return ret; + + ret = imx415_identify_model(sensor); + if (ret) + goto err_power; + + ret = imx415_subdev_init(sensor); + if (ret) + goto err_power; + + /* + * Enable runtime PM. As the device has been powered manually, mark it + * as active, and increase the usage count without resuming the device. + */ + pm_runtime_set_active(sensor->dev); + pm_runtime_get_noresume(sensor->dev); + pm_runtime_enable(sensor->dev); + + ret = v4l2_async_register_subdev_sensor(&sensor->subdev); + if (ret < 0) + goto err_pm; + + /* + * Finally, enable autosuspend and decrease the usage count. The device + * will get suspended after the autosuspend delay, turning the power + * off. + */ + pm_runtime_set_autosuspend_delay(sensor->dev, 1000); + pm_runtime_use_autosuspend(sensor->dev); + pm_runtime_put_autosuspend(sensor->dev); + + return 0; + +err_pm: + pm_runtime_disable(sensor->dev); + pm_runtime_put_noidle(sensor->dev); + imx415_subdev_cleanup(sensor); +err_power: + imx415_power_off(sensor); + return ret; +} + +static void imx415_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx415 *sensor = to_imx415(subdev); + + v4l2_async_unregister_subdev(subdev); + + imx415_subdev_cleanup(sensor); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(sensor->dev); + if (!pm_runtime_status_suspended(sensor->dev)) + imx415_power_off(sensor); + pm_runtime_set_suspended(sensor->dev); +} + +static int imx415_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx415 *sensor = to_imx415(subdev); + + return imx415_power_on(sensor); +} + +static int imx415_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct imx415 *sensor = to_imx415(subdev); + + imx415_power_off(sensor); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx415_pm_ops, imx415_runtime_suspend, + imx415_runtime_resume, NULL); + +static const struct of_device_id imx415_of_match[] = { + { .compatible = "sony,imx415" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, imx415_of_match); + +static struct i2c_driver imx415_driver = { + .probe_new = imx415_probe, + .remove = imx415_remove, + .driver = { + .name = "imx415", + .of_match_table = imx415_of_match, + .pm = pm_ptr(&imx415_pm_ops), + }, +}; + +module_i2c_driver(imx415_driver); + +MODULE_DESCRIPTION("Sony IMX415 image sensor driver"); +MODULE_AUTHOR("Gerald Loacker <gerald.loacker@wolfvision.net>"); +MODULE_AUTHOR("Michael Riesch <michael.riesch@wolfvision.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 25bf1132dbff..51921068931d 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -757,8 +757,9 @@ static int zilog_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) return 0; } -static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int ir_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); char *ir_codes = NULL; const char *name = NULL; u64 rc_proto = RC_PROTO_BIT_UNKNOWN; @@ -987,7 +988,7 @@ static struct i2c_driver ir_kbd_driver = { .driver = { .name = "ir-kbd-i2c", }, - .probe = ir_probe, + .probe_new = ir_probe, .remove = ir_remove, .id_table = ir_kbd_id, }; diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index 9c083cf14231..701038d6d19b 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -72,7 +72,7 @@ #define MAX9286_DATATYPE_USER_YUV_12BIT (10 << 0) #define MAX9286_DATATYPE_USER_24BIT (9 << 0) #define MAX9286_DATATYPE_RAW14 (8 << 0) -#define MAX9286_DATATYPE_RAW11 (7 << 0) +#define MAX9286_DATATYPE_RAW12 (7 << 0) #define MAX9286_DATATYPE_RAW10 (6 << 0) #define MAX9286_DATATYPE_RAW8 (5 << 0) #define MAX9286_DATATYPE_YUV422_10BIT (4 << 0) @@ -81,13 +81,21 @@ #define MAX9286_DATATYPE_RGB565 (1 << 0) #define MAX9286_DATATYPE_RGB888 (0 << 0) /* Register 0x15 */ +#define MAX9286_CSI_IMAGE_TYP BIT(7) #define MAX9286_VC(n) ((n) << 5) #define MAX9286_VCTYPE BIT(4) #define MAX9286_CSIOUTEN BIT(3) -#define MAX9286_0X15_RESV (3 << 0) +#define MAX9286_SWP_ENDIAN BIT(2) +#define MAX9286_EN_CCBSYB_CLK_STR BIT(1) +#define MAX9286_EN_GPI_CCBSYB BIT(0) /* Register 0x1b */ #define MAX9286_SWITCHIN(n) (1 << ((n) + 4)) #define MAX9286_ENEQ(n) (1 << (n)) +/* Register 0x1c */ +#define MAX9286_HIGHIMM(n) BIT((n) + 4) +#define MAX9286_I2CSEL BIT(2) +#define MAX9286_HIBW BIT(1) +#define MAX9286_BWS BIT(0) /* Register 0x27 */ #define MAX9286_LOCKED BIT(7) /* Register 0x31 */ @@ -136,9 +144,20 @@ #define MAX9286_N_PADS 5 #define MAX9286_SRC_PAD 4 +struct max9286_format_info { + u32 code; + u8 datatype; +}; + +struct max9286_i2c_speed { + u32 rate; + u8 mstbt; +}; + struct max9286_source { struct v4l2_subdev *sd; struct fwnode_handle *fwnode; + struct regulator *regulator; }; struct max9286_asd { @@ -168,13 +187,18 @@ struct max9286_priv { /* The initial reverse control channel amplitude. */ u32 init_rev_chan_mv; u32 rev_chan_mv; + u8 i2c_mstbt; + u32 bus_width; + bool use_gpio_poc; u32 gpio_poc[2]; struct v4l2_ctrl_handler ctrls; - struct v4l2_ctrl *pixelrate; + struct v4l2_ctrl *pixelrate_ctrl; + unsigned int pixelrate; struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS]; + struct v4l2_fract interval; /* Protects controls and fmt structures */ struct mutex mutex; @@ -214,6 +238,45 @@ static inline struct max9286_priv *sd_to_max9286(struct v4l2_subdev *sd) return container_of(sd, struct max9286_priv, sd); } +static const struct max9286_format_info max9286_formats[] = { + { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .datatype = MAX9286_DATATYPE_YUV422_8BIT, + }, { + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .datatype = MAX9286_DATATYPE_YUV422_8BIT, + }, { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .datatype = MAX9286_DATATYPE_YUV422_8BIT, + }, { + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .datatype = MAX9286_DATATYPE_YUV422_8BIT, + }, { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .datatype = MAX9286_DATATYPE_RAW12, + }, { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .datatype = MAX9286_DATATYPE_RAW12, + }, { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .datatype = MAX9286_DATATYPE_RAW12, + }, { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .datatype = MAX9286_DATATYPE_RAW12, + }, +}; + +static const struct max9286_i2c_speed max9286_i2c_speeds[] = { + { .rate = 8470, .mstbt = MAX9286_I2CMSTBT_8KBPS }, + { .rate = 28300, .mstbt = MAX9286_I2CMSTBT_28KBPS }, + { .rate = 84700, .mstbt = MAX9286_I2CMSTBT_84KBPS }, + { .rate = 105000, .mstbt = MAX9286_I2CMSTBT_105KBPS }, + { .rate = 173000, .mstbt = MAX9286_I2CMSTBT_173KBPS }, + { .rate = 339000, .mstbt = MAX9286_I2CMSTBT_339KBPS }, + { .rate = 533000, .mstbt = MAX9286_I2CMSTBT_533KBPS }, + { .rate = 837000, .mstbt = MAX9286_I2CMSTBT_837KBPS }, +}; + /* ----------------------------------------------------------------------------- * I2C IO */ @@ -334,7 +397,7 @@ error: static void max9286_configure_i2c(struct max9286_priv *priv, bool localack) { u8 config = MAX9286_I2CSLVSH_469NS_234NS | MAX9286_I2CSLVTO_1024US | - MAX9286_I2CMSTBT_105KBPS; + priv->i2c_mstbt; if (localack) config |= MAX9286_I2CLOCACK; @@ -475,6 +538,77 @@ static int max9286_check_config_link(struct max9286_priv *priv, return 0; } +static void max9286_set_video_format(struct max9286_priv *priv, + const struct v4l2_mbus_framefmt *format) +{ + const struct max9286_format_info *info = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { + if (max9286_formats[i].code == format->code) { + info = &max9286_formats[i]; + break; + } + } + + if (WARN_ON(!info)) + return; + + /* + * Video format setup: disable CSI output, set VC according to Link + * number, enable I2C clock stretching when CCBSY is low, enable CCBSY + * in external GPI-to-GPO mode. + */ + max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_EN_CCBSYB_CLK_STR | + MAX9286_EN_GPI_CCBSYB); + + /* Enable CSI-2 Lane D0-D3 only, DBL mode. */ + max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL | + MAX9286_CSILANECNT(priv->csi2_data_lanes) | + info->datatype); + + /* + * Enable HS/VS encoding, use HS as line valid source, use D14/15 for + * HS/VS, invert VS. + */ + max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_DESEL | + MAX9286_INVVS | MAX9286_HVSRC_D14); +} + +static void max9286_set_fsync_period(struct max9286_priv *priv) +{ + u32 fsync; + + if (!priv->interval.numerator || !priv->interval.denominator) { + /* + * Special case, a null interval enables automatic FRAMESYNC + * mode. FRAMESYNC is taken from the slowest link. + */ + max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ | + MAX9286_FSYNCMETH_AUTO); + return; + } + + /* + * Manual FRAMESYNC + * + * The FRAMESYNC generator is configured with a period expressed as a + * number of PCLK periods. + */ + fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator, + priv->interval.denominator); + + dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync, + priv->pixelrate); + + max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_OUT | + MAX9286_FSYNCMETH_MANUAL); + + max9286_write(priv, 0x06, (fsync >> 0) & 0xff); + max9286_write(priv, 0x07, (fsync >> 8) & 0xff); + max9286_write(priv, 0x08, (fsync >> 16) & 0xff); +} + /* ----------------------------------------------------------------------------- * V4L2 Subdev */ @@ -513,11 +647,13 @@ static int max9286_set_pixelrate(struct max9286_priv *priv) return -EINVAL; } + priv->pixelrate = pixelrate; + /* * The CSI-2 transmitter pixel rate is the single source rate multiplied * by the number of available sources. */ - return v4l2_ctrl_s_ctrl_int64(priv->pixelrate, + return v4l2_ctrl_s_ctrl_int64(priv->pixelrate_ctrl, pixelrate * priv->nsources); } @@ -657,6 +793,17 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable) int ret; if (enable) { + const struct v4l2_mbus_framefmt *format; + + /* + * Get the format from the first used sink pad, as all sink + * formats must be identical. + */ + format = &priv->fmt[__ffs(priv->bound_sources)]; + + max9286_set_video_format(priv, format); + max9286_set_fsync_period(priv); + /* * The frame sync between cameras is transmitted across the * reverse channel as GPIO. We must open all channels while @@ -698,13 +845,17 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable) } /* - * Enable CSI output, VC set according to link number. - * Bit 7 must be set (chip manual says it's 0 and reserved). + * Configure the CSI-2 output to line interleaved mode (W x (N + * x H), as opposed to the (N x W) x H mode that outputs the + * images stitched side-by-side) and enable it. */ - max9286_write(priv, 0x15, 0x80 | MAX9286_VCTYPE | - MAX9286_CSIOUTEN | MAX9286_0X15_RESV); + max9286_write(priv, 0x15, MAX9286_CSI_IMAGE_TYP | MAX9286_VCTYPE | + MAX9286_CSIOUTEN | MAX9286_EN_CCBSYB_CLK_STR | + MAX9286_EN_GPI_CCBSYB); } else { - max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV); + max9286_write(priv, 0x15, MAX9286_VCTYPE | + MAX9286_EN_CCBSYB_CLK_STR | + MAX9286_EN_GPI_CCBSYB); /* Stop all cameras. */ for_each_source(priv, source) @@ -716,6 +867,32 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +static int max9286_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct max9286_priv *priv = sd_to_max9286(sd); + + if (interval->pad != MAX9286_SRC_PAD) + return -EINVAL; + + interval->interval = priv->interval; + + return 0; +} + +static int max9286_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct max9286_priv *priv = sd_to_max9286(sd); + + if (interval->pad != MAX9286_SRC_PAD) + return -EINVAL; + + priv->interval = interval->interval; + + return 0; +} + static int max9286_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -749,22 +926,20 @@ static int max9286_set_fmt(struct v4l2_subdev *sd, { struct max9286_priv *priv = sd_to_max9286(sd); struct v4l2_mbus_framefmt *cfg_fmt; + unsigned int i; if (format->pad == MAX9286_SRC_PAD) return -EINVAL; - /* Refuse non YUV422 formats as we hardcode DT to 8 bit YUV422 */ - switch (format->format.code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - case MEDIA_BUS_FMT_VYUY8_1X16: - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YVYU8_1X16: - break; - default: - format->format.code = MEDIA_BUS_FMT_UYVY8_1X16; - break; + /* Validate the format. */ + for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { + if (max9286_formats[i].code == format->format.code) + break; } + if (i == ARRAY_SIZE(max9286_formats)) + format->format.code = max9286_formats[0].code; + cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad, format->which); if (!cfg_fmt) @@ -807,6 +982,8 @@ static int max9286_get_fmt(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops max9286_video_ops = { .s_stream = max9286_s_stream, + .g_frame_interval = max9286_g_frame_interval, + .s_frame_interval = max9286_s_frame_interval, }; static const struct v4l2_subdev_pad_ops max9286_pad_ops = { @@ -820,16 +997,20 @@ static const struct v4l2_subdev_ops max9286_subdev_ops = { .pad = &max9286_pad_ops, }; +static const struct v4l2_mbus_framefmt max9286_default_format = { + .width = 1280, + .height = 800, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .colorspace = V4L2_COLORSPACE_SRGB, + .field = V4L2_FIELD_NONE, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_DEFAULT, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, +}; + static void max9286_init_format(struct v4l2_mbus_framefmt *fmt) { - fmt->width = 1280; - fmt->height = 800; - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->field = V4L2_FIELD_NONE; - fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - fmt->quantization = V4L2_QUANTIZATION_DEFAULT; - fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; + *fmt = max9286_default_format; } static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) @@ -891,10 +1072,10 @@ static int max9286_v4l2_register(struct max9286_priv *priv) priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; v4l2_ctrl_handler_init(&priv->ctrls, 1); - priv->pixelrate = v4l2_ctrl_new_std(&priv->ctrls, - &max9286_ctrl_ops, - V4L2_CID_PIXEL_RATE, - 1, INT_MAX, 1, 50000000); + priv->pixelrate_ctrl = v4l2_ctrl_new_std(&priv->ctrls, + &max9286_ctrl_ops, + V4L2_CID_PIXEL_RATE, + 1, INT_MAX, 1, 50000000); priv->sd.ctrl_handler = &priv->ctrls; ret = priv->ctrls.error; @@ -932,6 +1113,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv) err_put_node: fwnode_handle_put(ep); err_async: + v4l2_ctrl_handler_free(&priv->ctrls); max9286_v4l2_notifier_unregister(priv); return ret; @@ -975,6 +1157,7 @@ static int max9286_setup(struct max9286_priv *priv) (2 << 6) | (1 << 4) | (0 << 2) | (3 << 0), /* 210x */ (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* 3210 */ }; + int cfg; /* * Set the I2C bus speed. @@ -993,24 +1176,27 @@ static int max9286_setup(struct max9286_priv *priv) max9286_write(priv, 0x0b, link_order[priv->route_mask]); max9286_write(priv, 0x69, (0xf & ~priv->route_mask)); - /* - * Video format setup: - * Disable CSI output, VC is set according to Link number. - */ - max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV); + max9286_set_video_format(priv, &max9286_default_format); + max9286_set_fsync_period(priv); - /* Enable CSI-2 Lane D0-D3 only, DBL mode, YUV422 8-bit. */ - max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL | - MAX9286_CSILANECNT(priv->csi2_data_lanes) | - MAX9286_DATATYPE_YUV422_8BIT); + cfg = max9286_read(priv, 0x1c); + if (cfg < 0) + return cfg; + + dev_dbg(&priv->client->dev, "power-up config: %s immunity, %u-bit bus\n", + cfg & MAX9286_HIGHIMM(0) ? "high" : "legacy", + cfg & MAX9286_BWS ? 32 : cfg & MAX9286_HIBW ? 27 : 24); - /* Automatic: FRAMESYNC taken from the slowest Link. */ - max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ | - MAX9286_FSYNCMETH_AUTO); + if (priv->bus_width) { + cfg &= ~(MAX9286_HIBW | MAX9286_BWS); - /* Enable HS/VS encoding, use D14/15 for HS/VS, invert VS. */ - max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_INVVS | - MAX9286_HVSRC_D14); + if (priv->bus_width == 27) + cfg |= MAX9286_HIBW; + else if (priv->bus_width == 32) + cfg |= MAX9286_BWS; + + max9286_write(priv, 0x1c, cfg); + } /* * The overlap window seems to provide additional validation by tracking @@ -1088,9 +1274,6 @@ static int max9286_parse_gpios(struct max9286_priv *priv) struct device *dev = &priv->client->dev; int ret; - /* GPIO values default to high */ - priv->gpio_state = BIT(0) | BIT(1); - /* * Parse the "gpio-poc" vendor property. If the property is not * specified the camera power is controlled by a regulator. @@ -1102,18 +1285,7 @@ static int max9286_parse_gpios(struct max9286_priv *priv) * If gpio lines are not used for the camera power, register * a gpio controller for consumers. */ - ret = max9286_register_gpio(priv); - if (ret) - return ret; - - priv->regulator = devm_regulator_get(dev, "poc"); - if (IS_ERR(priv->regulator)) { - return dev_err_probe(dev, PTR_ERR(priv->regulator), - "Unable to get PoC regulator (%ld)\n", - PTR_ERR(priv->regulator)); - } - - return 0; + return max9286_register_gpio(priv); } /* If the property is specified make sure it is well formed. */ @@ -1124,21 +1296,75 @@ static int max9286_parse_gpios(struct max9286_priv *priv) return -EINVAL; } + priv->use_gpio_poc = true; + return 0; +} + +static int max9286_poc_power_on(struct max9286_priv *priv) +{ + struct max9286_source *source; + unsigned int enabled = 0; + int ret; + + /* Enable the global regulator if available. */ + if (priv->regulator) + return regulator_enable(priv->regulator); + + if (priv->use_gpio_poc) + return max9286_gpio_set(priv, priv->gpio_poc[0], + !priv->gpio_poc[1]); + + /* Otherwise use the per-port regulators. */ + for_each_source(priv, source) { + ret = regulator_enable(source->regulator); + if (ret < 0) + goto error; + + enabled |= BIT(to_index(priv, source)); + } + return 0; + +error: + for_each_source(priv, source) { + if (enabled & BIT(to_index(priv, source))) + regulator_disable(source->regulator); + } + + return ret; +} + +static int max9286_poc_power_off(struct max9286_priv *priv) +{ + struct max9286_source *source; + int ret = 0; + + if (priv->regulator) + return regulator_disable(priv->regulator); + + if (priv->use_gpio_poc) + return max9286_gpio_set(priv, priv->gpio_poc[0], + priv->gpio_poc[1]); + + for_each_source(priv, source) { + int err; + + err = regulator_disable(source->regulator); + if (!ret) + ret = err; + } + + return ret; } static int max9286_poc_enable(struct max9286_priv *priv, bool enable) { int ret; - /* If the regulator is not available, use gpio to control power. */ - if (!priv->regulator) - ret = max9286_gpio_set(priv, priv->gpio_poc[0], - enable ^ priv->gpio_poc[1]); - else if (enable) - ret = regulator_enable(priv->regulator); + if (enable) + ret = max9286_poc_power_on(priv); else - ret = regulator_disable(priv->regulator); + ret = max9286_poc_power_off(priv); if (ret < 0) dev_err(&priv->client->dev, "Unable to turn power %s\n", @@ -1208,6 +1434,8 @@ static int max9286_parse_dt(struct max9286_priv *priv) struct device_node *node = NULL; unsigned int i2c_mux_mask = 0; u32 reverse_channel_microvolt; + u32 i2c_clk_freq = 105000; + unsigned int i; /* Balance the of_node_put() performed by of_find_node_by_name(). */ of_node_get(dev->of_node); @@ -1298,6 +1526,40 @@ static int max9286_parse_dt(struct max9286_priv *priv) } of_node_put(node); + of_property_read_u32(dev->of_node, "maxim,bus-width", &priv->bus_width); + switch (priv->bus_width) { + case 0: + /* + * The property isn't specified in the device tree, the driver + * will keep the default value selected by the BWS pin. + */ + case 24: + case 27: + case 32: + break; + default: + dev_err(dev, "Invalid %s value %u\n", "maxim,bus-width", + priv->bus_width); + return -EINVAL; + } + + of_property_read_u32(dev->of_node, "maxim,i2c-remote-bus-hz", + &i2c_clk_freq); + for (i = 0; i < ARRAY_SIZE(max9286_i2c_speeds); ++i) { + const struct max9286_i2c_speed *speed = &max9286_i2c_speeds[i]; + + if (speed->rate == i2c_clk_freq) { + priv->i2c_mstbt = speed->mstbt; + break; + } + } + + if (i == ARRAY_SIZE(max9286_i2c_speeds)) { + dev_err(dev, "Invalid %s value %u\n", "maxim,i2c-remote-bus-hz", + i2c_clk_freq); + return -EINVAL; + } + /* * Parse the initial value of the reverse channel amplitude from * the firmware interface and convert it to millivolts. @@ -1317,6 +1579,44 @@ static int max9286_parse_dt(struct max9286_priv *priv) return 0; } +static int max9286_get_poc_supplies(struct max9286_priv *priv) +{ + struct device *dev = &priv->client->dev; + struct max9286_source *source; + int ret; + + /* Start by getting the global regulator. */ + priv->regulator = devm_regulator_get_optional(dev, "poc"); + if (!IS_ERR(priv->regulator)) + return 0; + + if (PTR_ERR(priv->regulator) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(priv->regulator), + "Unable to get PoC regulator\n"); + + /* If there's no global regulator, get per-port regulators. */ + dev_dbg(dev, + "No global PoC regulator, looking for per-port regulators\n"); + priv->regulator = NULL; + + for_each_source(priv, source) { + unsigned int index = to_index(priv, source); + char name[10]; + + snprintf(name, sizeof(name), "port%u-poc", index); + source->regulator = devm_regulator_get(dev, name); + if (IS_ERR(source->regulator)) { + ret = PTR_ERR(source->regulator); + dev_err_probe(dev, ret, + "Unable to get port %u PoC regulator\n", + index); + return ret; + } + } + + return 0; +} + static int max9286_probe(struct i2c_client *client) { struct max9286_priv *priv; @@ -1330,10 +1630,19 @@ static int max9286_probe(struct i2c_client *client) priv->client = client; + /* GPIO values default to high */ + priv->gpio_state = BIT(0) | BIT(1); + + ret = max9286_parse_dt(priv); + if (ret) + goto err_cleanup_dt; + priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(priv->gpiod_pwdn)) - return PTR_ERR(priv->gpiod_pwdn); + if (IS_ERR(priv->gpiod_pwdn)) { + ret = PTR_ERR(priv->gpiod_pwdn); + goto err_cleanup_dt; + } gpiod_set_consumer_name(priv->gpiod_pwdn, "max9286-pwdn"); gpiod_set_value_cansleep(priv->gpiod_pwdn, 1); @@ -1360,9 +1669,11 @@ static int max9286_probe(struct i2c_client *client) if (ret) goto err_powerdown; - ret = max9286_parse_dt(priv); - if (ret) - goto err_powerdown; + if (!priv->use_gpio_poc) { + ret = max9286_get_poc_supplies(priv); + if (ret) + goto err_cleanup_dt; + } ret = max9286_init(priv); if (ret < 0) @@ -1370,10 +1681,10 @@ static int max9286_probe(struct i2c_client *client) return 0; -err_cleanup_dt: - max9286_cleanup_dt(priv); err_powerdown: gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); +err_cleanup_dt: + max9286_cleanup_dt(priv); return ret; } diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 4ce7a15a9884..12032e28b428 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -663,8 +663,9 @@ static const char * const opmode_str[] = { [OPMODE_AUTOSELECT] = "autodetect and autoselect", }; -static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int msp_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct msp_state *state; struct v4l2_subdev *sd; struct v4l2_ctrl_handler *hdl; @@ -891,7 +892,7 @@ static struct i2c_driver msp_driver = { .name = "msp3400", .pm = &msp3400_pm_ops, }, - .probe = msp_probe, + .probe_new = msp_probe, .remove = msp_remove, .id_table = msp_id, }; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 4ffc2f6e7db4..9e023a4b9bd1 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -1102,9 +1102,9 @@ done: return pdata; } -static int mt9p031_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int mt9p031_probe(struct i2c_client *client) { + const struct i2c_device_id *did = i2c_client_get_device_id(client); struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client); struct i2c_adapter *adapter = client->adapter; struct mt9p031 *mt9p031; @@ -1248,7 +1248,7 @@ static struct i2c_driver mt9p031_i2c_driver = { .of_match_table = of_match_ptr(mt9p031_of_match), .name = "mt9p031", }, - .probe = mt9p031_probe, + .probe_new = mt9p031_probe, .remove = mt9p031_remove, .id_table = mt9p031_id, }; diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index bc4388ccc2a8..7cfd4ebdd2e6 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -1044,9 +1044,9 @@ done: return pdata; } -static int mt9v032_probe(struct i2c_client *client, - const struct i2c_device_id *did) +static int mt9v032_probe(struct i2c_client *client) { + const struct i2c_device_id *did = i2c_client_get_device_id(client); struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client); struct mt9v032 *mt9v032; unsigned int i; @@ -1296,7 +1296,7 @@ static struct i2c_driver mt9v032_driver = { .name = "mt9v032", .of_match_table = of_match_ptr(mt9v032_of_match), }, - .probe = mt9v032_probe, + .probe_new = mt9v032_probe, .remove = mt9v032_remove, .id_table = mt9v032_id, }; diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index f3731f932a94..89d126240c34 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -629,8 +629,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740) V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov2740_test_pattern_menu) - 1, 0, 0, ov2740_test_pattern_menu); - if (ctrl_hdlr->error) + if (ctrl_hdlr->error) { + v4l2_ctrl_handler_free(ctrl_hdlr); return ctrl_hdlr->error; + } ov2740->sd.ctrl_handler = ctrl_hdlr; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index e0f908af581b..1536649b9e90 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -50,6 +50,7 @@ #define OV5640_REG_SYS_CTRL0 0x3008 #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 #define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 +#define OV5640_REG_SYS_CTRL0_SW_RST 0x82 #define OV5640_REG_CHIP_ID 0x300a #define OV5640_REG_IO_MIPI_CTRL00 0x300e #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 @@ -520,7 +521,18 @@ static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code) */ /* YUV422 UYVY VGA@30fps */ -static const struct v4l2_mbus_framefmt ov5640_default_fmt = { +static const struct v4l2_mbus_framefmt ov5640_csi2_default_fmt = { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .width = 640, + .height = 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB), + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB), + .field = V4L2_FIELD_NONE, +}; + +static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = { .code = MEDIA_BUS_FMT_UYVY8_2X8, .width = 640, .height = 480, @@ -532,7 +544,7 @@ static const struct v4l2_mbus_framefmt ov5640_default_fmt = { }; static const struct reg_value ov5640_init_setting[] = { - {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, + {0x3103, 0x11, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, @@ -2424,24 +2436,48 @@ static void ov5640_power(struct ov5640_dev *sensor, bool enable) gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); } -static void ov5640_reset(struct ov5640_dev *sensor) +/* + * From section 2.7 power up sequence: + * t0 + t1 + t2 >= 5ms Delay from DOVDD stable to PWDN pull down + * t3 >= 1ms Delay from PWDN pull down to RESETB pull up + * t4 >= 20ms Delay from RESETB pull up to SCCB (i2c) stable + * + * Some modules don't expose RESETB/PWDN pins directly, instead providing a + * "PWUP" GPIO which is wired through appropriate delays and inverters to the + * pins. + * + * In such cases, this gpio should be mapped to pwdn_gpio in the driver, and we + * should still toggle the pwdn_gpio below with the appropriate delays, while + * the calls to reset_gpio will be ignored. + */ +static void ov5640_powerup_sequence(struct ov5640_dev *sensor) { - if (!sensor->reset_gpio) - return; - - gpiod_set_value_cansleep(sensor->reset_gpio, 0); + if (sensor->pwdn_gpio) { + gpiod_set_value_cansleep(sensor->reset_gpio, 0); - /* camera power cycle */ - ov5640_power(sensor, false); - usleep_range(5000, 10000); - ov5640_power(sensor, true); - usleep_range(5000, 10000); + /* camera power cycle */ + ov5640_power(sensor, false); + usleep_range(5000, 10000); + ov5640_power(sensor, true); + usleep_range(5000, 10000); - gpiod_set_value_cansleep(sensor->reset_gpio, 1); - usleep_range(1000, 2000); + gpiod_set_value_cansleep(sensor->reset_gpio, 1); + usleep_range(1000, 2000); - gpiod_set_value_cansleep(sensor->reset_gpio, 0); + gpiod_set_value_cansleep(sensor->reset_gpio, 0); + } else { + /* software reset */ + ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, + OV5640_REG_SYS_CTRL0_SW_RST); + } usleep_range(20000, 25000); + + /* + * software standby: allows registers programming; + * exit at restore_mode() for CSI, s_stream(1) for DVP + */ + ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, + OV5640_REG_SYS_CTRL0_SW_PWDN); } static int ov5640_set_power_on(struct ov5640_dev *sensor) @@ -2464,8 +2500,7 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor) goto xclk_off; } - ov5640_reset(sensor); - ov5640_power(sensor, true); + ov5640_powerup_sequence(sensor); ret = ov5640_init_slave_id(sensor); if (ret) @@ -3316,6 +3351,7 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return 0; @@ -3391,6 +3427,7 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return ret; @@ -3458,7 +3495,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) /* Auto/manual gain */ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, 1023, 1, 0); ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, @@ -3710,8 +3747,10 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) out: mutex_unlock(&sensor->lock); - if (!enable || ret) + if (!enable || ret) { + pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); + } return ret; } @@ -3719,11 +3758,13 @@ out: static int ov5640_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *state) { + struct ov5640_dev *sensor = to_ov5640_dev(sd); struct v4l2_mbus_framefmt *fmt = v4l2_subdev_get_try_format(sd, state, 0); struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); - *fmt = ov5640_default_fmt; + *fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt : + ov5640_dvp_default_fmt; crop->left = OV5640_PIXEL_ARRAY_LEFT; crop->top = OV5640_PIXEL_ARRAY_TOP; @@ -3812,7 +3853,6 @@ static int ov5640_probe(struct i2c_client *client) * default init sequence initialize sensor to * YUV422 UYVY VGA@30fps */ - sensor->fmt = ov5640_default_fmt; sensor->frame_interval.numerator = 1; sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; sensor->current_fr = OV5640_30_FPS; @@ -3845,6 +3885,9 @@ static int ov5640_probe(struct i2c_client *client) return -EINVAL; } + sensor->fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt : + ov5640_dvp_default_fmt; + /* get system clock (xclk) */ sensor->xclk = devm_clk_get(dev, "xclk"); if (IS_ERR(sensor->xclk)) { @@ -3912,6 +3955,7 @@ static int ov5640_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index bc9fc3bc90c2..f79d908f4531 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1,15 +1,24 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017 Intel Corporation. +#include <asm/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> +#define OV5670_XVCLK_FREQ 19200000 + #define OV5670_REG_CHIP_ID 0x300a #define OV5670_CHIP_ID 0x005670 @@ -65,6 +74,10 @@ #define OV5670_REG_VALUE_16BIT 2 #define OV5670_REG_VALUE_24BIT 3 +/* Pixel Array */ +#define OV5670_NATIVE_WIDTH 2624 +#define OV5670_NATIVE_HEIGHT 1980 + /* Initial number of frames to skip to avoid possible garbage */ #define OV5670_NUM_OF_SKIP_FRAMES 2 @@ -83,6 +96,14 @@ struct ov5670_link_freq_config { const struct ov5670_reg_list reg_list; }; +static const char * const ov5670_supply_names[] = { + "avdd", /* Analog power */ + "dvdd", /* Digital power */ + "dovdd", /* Digital output power */ +}; + +#define OV5670_NUM_SUPPLIES ARRAY_SIZE(ov5670_supply_names) + struct ov5670_mode { /* Frame width in pixels */ u32 width; @@ -99,10 +120,25 @@ struct ov5670_mode { /* Link frequency needed for this resolution */ u32 link_freq_index; + /* Analog crop rectangle */ + const struct v4l2_rect *analog_crop; + /* Sensor register settings for this resolution */ const struct ov5670_reg_list reg_list; }; +/* + * All the modes supported by the driver are obtained by subsampling the + * full pixel array. The below values are reflected in registers from + * 0x3800-0x3807 in the modes register-value tables. + */ +static const struct v4l2_rect ov5670_analog_crop = { + .left = 12, + .top = 4, + .width = 2600, + .height = 1952, +}; + static const struct ov5670_reg mipi_data_rate_840mbps[] = { {0x0300, 0x04}, {0x0301, 0x00}, @@ -1750,66 +1786,73 @@ static const struct ov5670_mode supported_modes[] = { .height = 1944, .vts_def = OV5670_VTS_30FPS, .vts_min = OV5670_VTS_30FPS, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), .regs = mode_2592x1944_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 1296, .height = 972, .vts_def = OV5670_VTS_30FPS, .vts_min = 996, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1296x972_regs), .regs = mode_1296x972_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 648, .height = 486, .vts_def = OV5670_VTS_30FPS, .vts_min = 516, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_648x486_regs), .regs = mode_648x486_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 2560, .height = 1440, .vts_def = OV5670_VTS_30FPS, .vts_min = OV5670_VTS_30FPS, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2560x1440_regs), .regs = mode_2560x1440_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 1280, .height = 720, .vts_def = OV5670_VTS_30FPS, .vts_min = 1020, + + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), .regs = mode_1280x720_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, }, { .width = 640, .height = 360, .vts_def = OV5670_VTS_30FPS, .vts_min = 510, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + .analog_crop = &ov5670_analog_crop, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_640x360_regs), .regs = mode_640x360_regs, }, - .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, } }; @@ -1828,6 +1871,16 @@ struct ov5670 { /* Current mode */ const struct ov5670_mode *cur_mode; + /* xvclk input clock */ + struct clk *xvclk; + + /* Regulators */ + struct regulator_bulk_data supplies[OV5670_NUM_SUPPLIES]; + + /* Power-down and reset gpios. */ + struct gpio_desc *pwdn_gpio; /* PWDNB pin. */ + struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */ + /* To serialize asynchronus callbacks */ struct mutex mutex; @@ -1935,27 +1988,6 @@ static int ov5670_write_reg_list(struct ov5670 *ov5670, return ov5670_write_regs(ov5670, r_list->regs, r_list->num_of_regs); } -/* Open sub-device */ -static int ov5670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct ov5670 *ov5670 = to_ov5670(sd); - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); - - mutex_lock(&ov5670->mutex); - - /* Initialize try_fmt */ - try_fmt->width = ov5670->cur_mode->width; - try_fmt->height = ov5670->cur_mode->height; - try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - try_fmt->field = V4L2_FIELD_NONE; - - /* No crop or compose */ - mutex_unlock(&ov5670->mutex); - - return 0; -} - static int ov5670_update_digital_gain(struct ov5670 *ov5670, u32 d_gain) { int ret; @@ -2006,7 +2038,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) struct ov5670, ctrl_handler); struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); s64 max; - int ret = 0; + int ret; /* Propagate change of current control to all related controls */ switch (ctrl->id) { @@ -2045,7 +2077,13 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TEST_PATTERN: ret = ov5670_enable_test_pattern(ov5670, ctrl->val); break; + case V4L2_CID_HBLANK: + case V4L2_CID_LINK_FREQ: + case V4L2_CID_PIXEL_RATE: + ret = 0; + break; default: + ret = -EINVAL; dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); break; @@ -2155,6 +2193,28 @@ error: return ret; } +static int ov5670_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_try_format(sd, state, 0); + const struct ov5670_mode *default_mode = &supported_modes[0]; + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); + + fmt->width = default_mode->width; + fmt->height = default_mode->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); + + *crop = *default_mode->analog_crop; + + return 0; +} + static int ov5670_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -2404,6 +2464,49 @@ unlock_and_return: return ret; } +static int __maybe_unused ov5670_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5670 *ov5670 = to_ov5670(sd); + unsigned long delay_us; + int ret; + + ret = clk_prepare_enable(ov5670->xvclk); + if (ret) + return ret; + + ret = regulator_bulk_enable(OV5670_NUM_SUPPLIES, ov5670->supplies); + if (ret) { + clk_disable_unprepare(ov5670->xvclk); + return ret; + } + + gpiod_set_value_cansleep(ov5670->pwdn_gpio, 0); + gpiod_set_value_cansleep(ov5670->reset_gpio, 0); + + /* 8192 * 2 clock pulses before the first SCCB transaction. */ + delay_us = DIV_ROUND_UP(8192 * 2 * 1000, + DIV_ROUND_UP(OV5670_XVCLK_FREQ, 1000)); + fsleep(delay_us); + + return 0; +} + +static int __maybe_unused ov5670_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5670 *ov5670 = to_ov5670(sd); + + gpiod_set_value_cansleep(ov5670->reset_gpio, 1); + gpiod_set_value_cansleep(ov5670->pwdn_gpio, 1); + regulator_bulk_disable(OV5670_NUM_SUPPLIES, ov5670->supplies); + clk_disable_unprepare(ov5670->xvclk); + + return 0; +} + static int __maybe_unused ov5670_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); @@ -2438,15 +2541,64 @@ static const struct v4l2_subdev_core_ops ov5670_core_ops = { .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; +static const struct v4l2_rect * +__ov5670_get_pad_crop(struct ov5670 *sensor, struct v4l2_subdev_state *state, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + const struct ov5670_mode *mode = sensor->cur_mode; + + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(&sensor->sd, state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return mode->analog_crop; + } + + return NULL; +} + +static int ov5670_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct ov5670 *sensor = to_ov5670(subdev); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + mutex_lock(&sensor->mutex); + sel->r = *__ov5670_get_pad_crop(sensor, state, sel->pad, + sel->which); + mutex_unlock(&sensor->mutex); + break; + case V4L2_SEL_TGT_NATIVE_SIZE: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = OV5670_NATIVE_WIDTH; + sel->r.height = OV5670_NATIVE_HEIGHT; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r = ov5670_analog_crop; + break; + default: + return -EINVAL; + } + + return 0; +} + static const struct v4l2_subdev_video_ops ov5670_video_ops = { .s_stream = ov5670_set_stream, }; static const struct v4l2_subdev_pad_ops ov5670_pad_ops = { + .init_cfg = ov5670_init_cfg, .enum_mbus_code = ov5670_enum_mbus_code, .get_fmt = ov5670_get_pad_format, .set_fmt = ov5670_set_pad_format, .enum_frame_size = ov5670_enum_frame_size, + .get_selection = ov5670_get_selection, + .set_selection = ov5670_get_selection, }; static const struct v4l2_subdev_sensor_ops ov5670_sensor_ops = { @@ -2464,9 +2616,34 @@ static const struct media_entity_operations ov5670_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -static const struct v4l2_subdev_internal_ops ov5670_internal_ops = { - .open = ov5670_open, -}; +static int ov5670_regulators_probe(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + unsigned int i; + + for (i = 0; i < OV5670_NUM_SUPPLIES; i++) + ov5670->supplies[i].supply = ov5670_supply_names[i]; + + return devm_regulator_bulk_get(&client->dev, OV5670_NUM_SUPPLIES, + ov5670->supplies); +} + +static int ov5670_gpio_probe(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + + ov5670->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", + GPIOD_OUT_LOW); + if (IS_ERR(ov5670->pwdn_gpio)) + return PTR_ERR(ov5670->pwdn_gpio); + + ov5670->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov5670->reset_gpio)) + return PTR_ERR(ov5670->reset_gpio); + + return 0; +} static int ov5670_probe(struct i2c_client *client) { @@ -2476,10 +2653,6 @@ static int ov5670_probe(struct i2c_client *client) bool full_power; int ret; - device_property_read_u32(&client->dev, "clock-frequency", &input_clk); - if (input_clk != 19200000) - return -EINVAL; - ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL); if (!ov5670) { ret = -ENOMEM; @@ -2487,16 +2660,50 @@ static int ov5670_probe(struct i2c_client *client) goto error_print; } + ov5670->xvclk = devm_clk_get(&client->dev, NULL); + if (!IS_ERR_OR_NULL(ov5670->xvclk)) + input_clk = clk_get_rate(ov5670->xvclk); + else if (PTR_ERR(ov5670->xvclk) == -ENOENT) + device_property_read_u32(&client->dev, "clock-frequency", + &input_clk); + else + return dev_err_probe(&client->dev, PTR_ERR(ov5670->xvclk), + "error getting clock\n"); + + if (input_clk != OV5670_XVCLK_FREQ) { + dev_err(&client->dev, + "Unsupported clock frequency %u\n", input_clk); + return -EINVAL; + } + /* Initialize subdev */ v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops); + ret = ov5670_regulators_probe(ov5670); + if (ret) { + err_msg = "Regulators probe failed"; + goto error_print; + } + + ret = ov5670_gpio_probe(ov5670); + if (ret) { + err_msg = "GPIO probe failed"; + goto error_print; + } + full_power = acpi_dev_state_d0(&client->dev); if (full_power) { + ret = ov5670_runtime_resume(&client->dev); + if (ret) { + err_msg = "Power up failed"; + goto error_print; + } + /* Check module identity */ ret = ov5670_identify_module(ov5670); if (ret) { err_msg = "ov5670_identify_module() error"; - goto error_print; + goto error_power_off; } } @@ -2511,7 +2718,6 @@ static int ov5670_probe(struct i2c_client *client) goto error_mutex_destroy; } - ov5670->sd.internal_ops = &ov5670_internal_ops; ov5670->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; ov5670->sd.entity.ops = &ov5670_subdev_entity_ops; @@ -2525,24 +2731,27 @@ static int ov5670_probe(struct i2c_client *client) goto error_handler_free; } - /* Async register for subdev */ - ret = v4l2_async_register_subdev_sensor(&ov5670->sd); - if (ret < 0) { - err_msg = "v4l2_async_register_subdev() error"; - goto error_entity_cleanup; - } - ov5670->streaming = false; /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); + + /* Async register for subdev */ + ret = v4l2_async_register_subdev_sensor(&ov5670->sd); + if (ret < 0) { + err_msg = "v4l2_async_register_subdev() error"; + goto error_pm_disable; + } + pm_runtime_idle(&client->dev); return 0; -error_entity_cleanup: +error_pm_disable: + pm_runtime_disable(&client->dev); + media_entity_cleanup(&ov5670->sd.entity); error_handler_free: @@ -2551,6 +2760,10 @@ error_handler_free: error_mutex_destroy: mutex_destroy(&ov5670->mutex); +error_power_off: + if (full_power) + ov5670_runtime_suspend(&client->dev); + error_print: dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret); @@ -2568,10 +2781,12 @@ static void ov5670_remove(struct i2c_client *client) mutex_destroy(&ov5670->mutex); pm_runtime_disable(&client->dev); + ov5670_runtime_suspend(&client->dev); } static const struct dev_pm_ops ov5670_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume) + SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL) }; #ifdef CONFIG_ACPI @@ -2583,11 +2798,18 @@ static const struct acpi_device_id ov5670_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ov5670_acpi_ids); #endif +static const struct of_device_id ov5670_of_ids[] = { + { .compatible = "ovti,ov5670" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov5670_of_ids); + static struct i2c_driver ov5670_i2c_driver = { .driver = { .name = "ov5670", .pm = &ov5670_pm_ops, .acpi_match_table = ACPI_PTR(ov5670_acpi_ids), + .of_match_table = ov5670_of_ids, }, .probe_new = ov5670_probe, .remove = ov5670_remove, diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index 94dc8cb7a7c0..d55180b3b7aa 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -3,10 +3,14 @@ #include <asm/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -17,7 +21,7 @@ #define OV5675_LINK_FREQ_450MHZ 450000000ULL #define OV5675_SCLK 90000000LL -#define OV5675_MCLK 19200000 +#define OV5675_XVCLK_19_2 19200000 #define OV5675_DATA_LANES 2 #define OV5675_RGB_DEPTH 10 @@ -76,6 +80,14 @@ #define to_ov5675(_sd) container_of(_sd, struct ov5675, sd) +static const char * const ov5675_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV5675_NUM_SUPPLIES ARRAY_SIZE(ov5675_supply_names) + enum { OV5675_LINK_FREQ_900MBPS, }; @@ -484,6 +496,9 @@ struct ov5675 { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV5675_NUM_SUPPLIES]; /* V4L2 Controls */ struct v4l2_ctrl *link_freq; @@ -764,12 +779,14 @@ static const struct v4l2_ctrl_ops ov5675_ctrl_ops = { static int ov5675_init_controls(struct ov5675 *ov5675) { + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max, h_blank; int ret; ctrl_hdlr = &ov5675->ctrl_handler; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); if (ret) return ret; @@ -820,12 +837,28 @@ static int ov5675_init_controls(struct ov5675 *ov5675) v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - if (ctrl_hdlr->error) + if (ctrl_hdlr->error) { + v4l2_ctrl_handler_free(ctrl_hdlr); return ctrl_hdlr->error; + } + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov5675_ctrl_ops, + &props); + if (ret) + goto error; ov5675->sd.ctrl_handler = ctrl_hdlr; return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; } static void ov5675_update_pad_format(const struct ov5675_mode *mode, @@ -944,6 +977,56 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) return ret; } +static int ov5675_power_off(struct device *dev) +{ + /* 512 xvclk cycles after the last SCCB transation or MIPI frame end */ + u32 delay_us = DIV_ROUND_UP(512, OV5675_XVCLK_19_2 / 1000 / 1000); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5675 *ov5675 = to_ov5675(sd); + + usleep_range(delay_us, delay_us * 2); + + clk_disable_unprepare(ov5675->xvclk); + gpiod_set_value_cansleep(ov5675->reset_gpio, 1); + regulator_bulk_disable(OV5675_NUM_SUPPLIES, ov5675->supplies); + + return 0; +} + +static int ov5675_power_on(struct device *dev) +{ + u32 delay_us = DIV_ROUND_UP(8192, OV5675_XVCLK_19_2 / 1000 / 1000); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5675 *ov5675 = to_ov5675(sd); + int ret; + + ret = clk_prepare_enable(ov5675->xvclk); + if (ret < 0) { + dev_err(dev, "failed to enable xvclk: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ov5675->reset_gpio, 1); + + ret = regulator_bulk_enable(OV5675_NUM_SUPPLIES, ov5675->supplies); + if (ret) { + clk_disable_unprepare(ov5675->xvclk); + return ret; + } + + /* Reset pulse should be at least 2ms and reset gpio released only once + * regulators are stable. + */ + usleep_range(2000, 2200); + + gpiod_set_value_cansleep(ov5675->reset_gpio, 0); + + /* 8192 xvclk cycles prior to the first SCCB transation */ + usleep_range(delay_us, delay_us * 2); + + return 0; +} + static int __maybe_unused ov5675_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); @@ -1040,6 +1123,31 @@ static int ov5675_get_format(struct v4l2_subdev *sd, return 0; } +static int ov5675_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = 2624; + sel->r.height = 2000; + return 0; + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = 16; + sel->r.left = 16; + sel->r.width = 2592; + sel->r.height = 1944; + return 0; + } + return -EINVAL; +} + static int ov5675_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -1089,6 +1197,7 @@ static const struct v4l2_subdev_video_ops ov5675_video_ops = { static const struct v4l2_subdev_pad_ops ov5675_pad_ops = { .set_fmt = ov5675_set_format, .get_fmt = ov5675_get_format, + .get_selection = ov5675_get_selection, .enum_mbus_code = ov5675_enum_mbus_code, .enum_frame_size = ov5675_enum_frame_size, }; @@ -1106,32 +1215,60 @@ static const struct v4l2_subdev_internal_ops ov5675_internal_ops = { .open = ov5675_open, }; -static int ov5675_check_hwcfg(struct device *dev) +static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev) { struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; + u32 xvclk_rate; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + ov5675->xvclk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(ov5675->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov5675->xvclk), + "failed to get xvclk: %ld\n", + PTR_ERR(ov5675->xvclk)); - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; + if (ov5675->xvclk) { + xvclk_rate = clk_get_rate(ov5675->xvclk); + } else { + ret = fwnode_property_read_u32(fwnode, "clock-frequency", + &xvclk_rate); + + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } } - if (mclk != OV5675_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); + if (xvclk_rate != OV5675_XVCLK_19_2) { + dev_err(dev, "external clock rate %u is unsupported", + xvclk_rate); return -EINVAL; } + ov5675->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov5675->reset_gpio)) { + ret = PTR_ERR(ov5675->reset_gpio); + dev_err(dev, "failed to get reset-gpios: %d\n", ret); + return ret; + } + + for (i = 0; i < OV5675_NUM_SUPPLIES; i++) + ov5675->supplies[i].supply = ov5675_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, OV5675_NUM_SUPPLIES, + ov5675->supplies); + if (ret) + return ret; + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -1185,6 +1322,10 @@ static void ov5675_remove(struct i2c_client *client) v4l2_ctrl_handler_free(sd->ctrl_handler); pm_runtime_disable(&client->dev); mutex_destroy(&ov5675->mutex); + + if (!pm_runtime_status_suspended(&client->dev)) + ov5675_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); } static int ov5675_probe(struct i2c_client *client) @@ -1193,25 +1334,31 @@ static int ov5675_probe(struct i2c_client *client) bool full_power; int ret; - ret = ov5675_check_hwcfg(&client->dev); + ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL); + if (!ov5675) + return -ENOMEM; + + ret = ov5675_get_hwcfg(ov5675, &client->dev); if (ret) { - dev_err(&client->dev, "failed to check HW configuration: %d", + dev_err(&client->dev, "failed to get HW configuration: %d", ret); return ret; } - ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL); - if (!ov5675) - return -ENOMEM; - v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); + ret = ov5675_power_on(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to power on: %d\n", ret); + return ret; + } + full_power = acpi_dev_state_d0(&client->dev); if (full_power) { ret = ov5675_identify_module(ov5675); if (ret) { dev_err(&client->dev, "failed to find sensor: %d", ret); - return ret; + goto probe_power_off; } } @@ -1241,11 +1388,6 @@ static int ov5675_probe(struct i2c_client *client) goto probe_error_media_entity_cleanup; } - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Enable runtime PM and turn off the device. - */ - /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); @@ -1260,12 +1402,15 @@ probe_error_media_entity_cleanup: probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler); mutex_destroy(&ov5675->mutex); +probe_power_off: + ov5675_power_off(&client->dev); return ret; } static const struct dev_pm_ops ov5675_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume) + SET_RUNTIME_PM_OPS(ov5675_power_off, ov5675_power_on, NULL) }; #ifdef CONFIG_ACPI @@ -1277,11 +1422,18 @@ static const struct acpi_device_id ov5675_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ov5675_acpi_ids); #endif +static const struct of_device_id ov5675_of_match[] = { + { .compatible = "ovti,ov5675", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov5675_of_match); + static struct i2c_driver ov5675_i2c_driver = { .driver = { .name = "ov5675", .pm = &ov5675_pm_ops, .acpi_match_table = ACPI_PTR(ov5675_acpi_ids), + .of_match_table = ov5675_of_match, }, .probe_new = ov5675_probe, .remove = ov5675_remove, diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 11d3bef65d43..b1bb0833571e 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1840,16 +1840,16 @@ static int ov7670_parse_dt(struct device *dev, if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) { dev_err(dev, "Unsupported media bus type\n"); - return ret; + return -EINVAL; } info->mbus_config = bus_cfg.bus.parallel.flags; return 0; } -static int ov7670_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov7670_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct v4l2_fract tpf; struct v4l2_subdev *sd; struct ov7670_info *info; @@ -2038,7 +2038,7 @@ static struct i2c_driver ov7670_driver = { .name = "ov7670", .of_match_table = of_match_ptr(ov7670_of_match), }, - .probe = ov7670_probe, + .probe_new = ov7670_probe, .remove = ov7670_remove, .id_table = ov7670_id, }; diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 4189e3fc3d53..a238e63425f8 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -1462,7 +1462,7 @@ static int ov772x_probe(struct i2c_client *client) priv->subdev.ctrl_handler = &priv->hdl; if (priv->hdl.error) { ret = priv->hdl.error; - goto error_mutex_destroy; + goto error_ctrl_free; } priv->clk = clk_get(&client->dev, NULL); @@ -1515,7 +1515,6 @@ error_clk_put: clk_put(priv->clk); error_ctrl_free: v4l2_ctrl_handler_free(&priv->hdl); -error_mutex_destroy: mutex_destroy(&priv->lock); return ret; diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c new file mode 100644 index 000000000000..9ca8a17bfbb9 --- /dev/null +++ b/drivers/media/i2c/ov8858.c @@ -0,0 +1,2008 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Jacopo Mondi <jacopo.mondi@ideasonboard.com> + * Copyright (C) 2022 Nicholas Roth <nicholas@rothemail.net> + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + */ + +#include <asm/unaligned.h> + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +#include <media/media-entity.h> +#include <media/v4l2-async.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +#define OV8858_LINK_FREQ 360000000U +#define OV8858_XVCLK_FREQ 24000000 + +#define OV8858_REG_SIZE_SHIFT 16 +#define OV8858_REG_ADDR_MASK 0xffff +#define OV8858_REG_8BIT(n) ((1U << OV8858_REG_SIZE_SHIFT) | (n)) +#define OV8858_REG_16BIT(n) ((2U << OV8858_REG_SIZE_SHIFT) | (n)) +#define OV8858_REG_24BIT(n) ((3U << OV8858_REG_SIZE_SHIFT) | (n)) + +#define OV8858_REG_SC_CTRL0100 OV8858_REG_8BIT(0x0100) +#define OV8858_MODE_SW_STANDBY 0x0 +#define OV8858_MODE_STREAMING 0x1 + +#define OV8858_REG_CHIP_ID OV8858_REG_24BIT(0x300a) +#define OV8858_CHIP_ID 0x008858 + +#define OV8858_REG_SUB_ID OV8858_REG_8BIT(0x302a) +#define OV8858_R1A 0xb0 +#define OV8858_R2A 0xb2 + +#define OV8858_REG_LONG_EXPO OV8858_REG_24BIT(0x3500) +#define OV8858_EXPOSURE_MIN 4 +#define OV8858_EXPOSURE_STEP 1 +#define OV8858_EXPOSURE_MARGIN 4 + +#define OV8858_REG_LONG_GAIN OV8858_REG_16BIT(0x3508) +#define OV8858_LONG_GAIN_MIN 0x0 +#define OV8858_LONG_GAIN_MAX 0x7ff +#define OV8858_LONG_GAIN_STEP 1 +#define OV8858_LONG_GAIN_DEFAULT 0x80 + +#define OV8858_REG_LONG_DIGIGAIN OV8858_REG_16BIT(0x350a) +#define OV8858_LONG_DIGIGAIN_H_MASK 0x3fc0 +#define OV8858_LONG_DIGIGAIN_L_MASK 0x3f +#define OV8858_LONG_DIGIGAIN_H_SHIFT 2 +#define OV8858_LONG_DIGIGAIN_MIN 0x0 +#define OV8858_LONG_DIGIGAIN_MAX 0x3fff +#define OV8858_LONG_DIGIGAIN_STEP 1 +#define OV8858_LONG_DIGIGAIN_DEFAULT 0x200 + +#define OV8858_REG_VTS OV8858_REG_16BIT(0x380e) +#define OV8858_VTS_MAX 0x7fff + +#define OV8858_REG_TEST_PATTERN OV8858_REG_8BIT(0x5e00) +#define OV8858_TEST_PATTERN_ENABLE 0x80 +#define OV8858_TEST_PATTERN_DISABLE 0x0 + +#define REG_NULL 0xffff + +static const char * const ov8858_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +struct regval { + u16 addr; + u8 val; +}; + +struct regval_modes { + const struct regval *mode_2lanes; + const struct regval *mode_4lanes; +}; + +struct ov8858_mode { + u32 width; + u32 height; + u32 hts_def; + u32 vts_def; + u32 exp_def; + const struct regval_modes reg_modes; +}; + +struct ov8858 { + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct gpio_desc *pwdn_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(ov8858_supply_names)]; + + struct v4l2_subdev subdev; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + + const struct regval *global_regs; + + unsigned int num_lanes; +}; + +static inline struct ov8858 *sd_to_ov8858(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov8858, subdev); +} + +static const struct regval ov8858_global_regs_r1a[] = { + {0x0100, 0x00}, + {0x0100, 0x00}, + {0x0100, 0x00}, + {0x0100, 0x00}, + {0x0302, 0x1e}, + {0x0303, 0x00}, + {0x0304, 0x03}, + {0x030e, 0x00}, + {0x030f, 0x09}, + {0x0312, 0x01}, + {0x031e, 0x0c}, + {0x3600, 0x00}, + {0x3601, 0x00}, + {0x3602, 0x00}, + {0x3603, 0x00}, + {0x3604, 0x22}, + {0x3605, 0x30}, + {0x3606, 0x00}, + {0x3607, 0x20}, + {0x3608, 0x11}, + {0x3609, 0x28}, + {0x360a, 0x00}, + {0x360b, 0x06}, + {0x360c, 0xdc}, + {0x360d, 0x40}, + {0x360e, 0x0c}, + {0x360f, 0x20}, + {0x3610, 0x07}, + {0x3611, 0x20}, + {0x3612, 0x88}, + {0x3613, 0x80}, + {0x3614, 0x58}, + {0x3615, 0x00}, + {0x3616, 0x4a}, + {0x3617, 0xb0}, + {0x3618, 0x56}, + {0x3619, 0x70}, + {0x361a, 0x99}, + {0x361b, 0x00}, + {0x361c, 0x07}, + {0x361d, 0x00}, + {0x361e, 0x00}, + {0x361f, 0x00}, + {0x3638, 0xff}, + {0x3633, 0x0c}, + {0x3634, 0x0c}, + {0x3635, 0x0c}, + {0x3636, 0x0c}, + {0x3645, 0x13}, + {0x3646, 0x83}, + {0x364a, 0x07}, + {0x3015, 0x01}, + {0x3018, 0x32}, + {0x3020, 0x93}, + {0x3022, 0x01}, + {0x3031, 0x0a}, + {0x3034, 0x00}, + {0x3106, 0x01}, + {0x3305, 0xf1}, + {0x3308, 0x00}, + {0x3309, 0x28}, + {0x330a, 0x00}, + {0x330b, 0x20}, + {0x330c, 0x00}, + {0x330d, 0x00}, + {0x330e, 0x00}, + {0x330f, 0x40}, + {0x3307, 0x04}, + {0x3500, 0x00}, + {0x3501, 0x4d}, + {0x3502, 0x40}, + {0x3503, 0x00}, + {0x3505, 0x80}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3700, 0x18}, + {0x3701, 0x0c}, + {0x3702, 0x28}, + {0x3703, 0x19}, + {0x3704, 0x14}, + {0x3705, 0x00}, + {0x3706, 0x35}, + {0x3707, 0x04}, + {0x3708, 0x24}, + {0x3709, 0x33}, + {0x370a, 0x00}, + {0x370b, 0xb5}, + {0x370c, 0x04}, + {0x3718, 0x12}, + {0x3719, 0x31}, + {0x3712, 0x42}, + {0x3714, 0x24}, + {0x371e, 0x19}, + {0x371f, 0x40}, + {0x3720, 0x05}, + {0x3721, 0x05}, + {0x3724, 0x06}, + {0x3725, 0x01}, + {0x3726, 0x06}, + {0x3728, 0x05}, + {0x3729, 0x02}, + {0x372a, 0x03}, + {0x372b, 0x53}, + {0x372c, 0xa3}, + {0x372d, 0x53}, + {0x372e, 0x06}, + {0x372f, 0x10}, + {0x3730, 0x01}, + {0x3731, 0x06}, + {0x3732, 0x14}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x3736, 0x20}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373e, 0x03}, + {0x3755, 0x10}, + {0x3758, 0x00}, + {0x3759, 0x4c}, + {0x375a, 0x06}, + {0x375b, 0x13}, + {0x375c, 0x20}, + {0x375d, 0x02}, + {0x375e, 0x00}, + {0x375f, 0x14}, + {0x3768, 0x22}, + {0x3769, 0x44}, + {0x376a, 0x44}, + {0x3761, 0x00}, + {0x3762, 0x00}, + {0x3763, 0x00}, + {0x3766, 0xff}, + {0x376b, 0x00}, + {0x3772, 0x23}, + {0x3773, 0x02}, + {0x3774, 0x16}, + {0x3775, 0x12}, + {0x3776, 0x04}, + {0x3777, 0x00}, + {0x3778, 0x1b}, + {0x37a0, 0x44}, + {0x37a1, 0x3d}, + {0x37a2, 0x3d}, + {0x37a3, 0x00}, + {0x37a4, 0x00}, + {0x37a5, 0x00}, + {0x37a6, 0x00}, + {0x37a7, 0x44}, + {0x37a8, 0x4c}, + {0x37a9, 0x4c}, + {0x3760, 0x00}, + {0x376f, 0x01}, + {0x37aa, 0x44}, + {0x37ab, 0x2e}, + {0x37ac, 0x2e}, + {0x37ad, 0x33}, + {0x37ae, 0x0d}, + {0x37af, 0x0d}, + {0x37b0, 0x00}, + {0x37b1, 0x00}, + {0x37b2, 0x00}, + {0x37b3, 0x42}, + {0x37b4, 0x42}, + {0x37b5, 0x33}, + {0x37b6, 0x00}, + {0x37b7, 0x00}, + {0x37b8, 0x00}, + {0x37b9, 0xff}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x0c}, + {0x3804, 0x0c}, + {0x3805, 0xd3}, + {0x3806, 0x09}, + {0x3807, 0xa3}, + {0x3808, 0x06}, + {0x3809, 0x60}, + {0x380a, 0x04}, + {0x380b, 0xc8}, + {0x380c, 0x07}, + {0x380d, 0x88}, + {0x380e, 0x04}, + {0x380f, 0xdc}, + {0x3810, 0x00}, + {0x3811, 0x04}, + {0x3813, 0x02}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3820, 0x00}, + {0x3821, 0x67}, + {0x382a, 0x03}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x18}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3d85, 0x14}, + {0x3f08, 0x08}, + {0x3f0a, 0x80}, + {0x4000, 0xf1}, + {0x4001, 0x10}, + {0x4005, 0x10}, + {0x4002, 0x27}, + {0x4009, 0x81}, + {0x400b, 0x0c}, + {0x401b, 0x00}, + {0x401d, 0x00}, + {0x4020, 0x00}, + {0x4021, 0x04}, + {0x4022, 0x04}, + {0x4023, 0xb9}, + {0x4024, 0x05}, + {0x4025, 0x2a}, + {0x4026, 0x05}, + {0x4027, 0x2b}, + {0x4028, 0x00}, + {0x4029, 0x02}, + {0x402a, 0x04}, + {0x402b, 0x04}, + {0x402c, 0x02}, + {0x402d, 0x02}, + {0x402e, 0x08}, + {0x402f, 0x02}, + {0x401f, 0x00}, + {0x4034, 0x3f}, + {0x403d, 0x04}, + {0x4300, 0xff}, + {0x4301, 0x00}, + {0x4302, 0x0f}, + {0x4316, 0x00}, + {0x4500, 0x38}, + {0x4503, 0x18}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x481f, 0x32}, + {0x4837, 0x16}, + {0x4850, 0x10}, + {0x4851, 0x32}, + {0x4b00, 0x2a}, + {0x4b0d, 0x00}, + {0x4d00, 0x04}, + {0x4d01, 0x18}, + {0x4d02, 0xc3}, + {0x4d03, 0xff}, + {0x4d04, 0xff}, + {0x4d05, 0xff}, + {0x5000, 0x7e}, + {0x5001, 0x01}, + {0x5002, 0x08}, + {0x5003, 0x20}, + {0x5046, 0x12}, + {0x5901, 0x00}, + {0x5e00, 0x00}, + {0x5e01, 0x41}, + {0x382d, 0x7f}, + {0x4825, 0x3a}, + {0x4826, 0x40}, + {0x4808, 0x25}, + {REG_NULL, 0x00}, +}; + +static const struct regval ov8858_global_regs_r2a_2lane[] = { + /* + * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz. + * v00_01_00 (05/29/2014) : initial setting + * AM19 : 3617 <- 0xC0 + * AM20 : change FWC_6K_EN to be default 0x3618=0x5a + */ + {0x0103, 0x01}, /* software reset */ + {0x0100, 0x00}, /* software standby */ + {0x0302, 0x1e}, /* pll1_multi */ + {0x0303, 0x00}, /* pll1_divm */ + {0x0304, 0x03}, /* pll1_div_mipi */ + {0x030e, 0x02}, /* pll2_rdiv */ + {0x030f, 0x04}, /* pll2_divsp */ + {0x0312, 0x03}, /* pll2_pre_div0, pll2_r_divdac */ + {0x031e, 0x0c}, /* pll1_no_lat */ + {0x3600, 0x00}, + {0x3601, 0x00}, + {0x3602, 0x00}, + {0x3603, 0x00}, + {0x3604, 0x22}, + {0x3605, 0x20}, + {0x3606, 0x00}, + {0x3607, 0x20}, + {0x3608, 0x11}, + {0x3609, 0x28}, + {0x360a, 0x00}, + {0x360b, 0x05}, + {0x360c, 0xd4}, + {0x360d, 0x40}, + {0x360e, 0x0c}, + {0x360f, 0x20}, + {0x3610, 0x07}, + {0x3611, 0x20}, + {0x3612, 0x88}, + {0x3613, 0x80}, + {0x3614, 0x58}, + {0x3615, 0x00}, + {0x3616, 0x4a}, + {0x3617, 0x90}, + {0x3618, 0x5a}, + {0x3619, 0x70}, + {0x361a, 0x99}, + {0x361b, 0x0a}, + {0x361c, 0x07}, + {0x361d, 0x00}, + {0x361e, 0x00}, + {0x361f, 0x00}, + {0x3638, 0xff}, + {0x3633, 0x0f}, + {0x3634, 0x0f}, + {0x3635, 0x0f}, + {0x3636, 0x12}, + {0x3645, 0x13}, + {0x3646, 0x83}, + {0x364a, 0x07}, + {0x3015, 0x00}, + {0x3018, 0x32}, /* MIPI 2 lane */ + {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */ + {0x3022, 0x01}, /* pd_mipi enable when rst_sync */ + {0x3031, 0x0a}, /* MIPI 10-bit mode */ + {0x3034, 0x00}, + {0x3106, 0x01}, /* sclk_div, sclk_pre_div */ + {0x3305, 0xf1}, + {0x3308, 0x00}, + {0x3309, 0x28}, + {0x330a, 0x00}, + {0x330b, 0x20}, + {0x330c, 0x00}, + {0x330d, 0x00}, + {0x330e, 0x00}, + {0x330f, 0x40}, + {0x3307, 0x04}, + {0x3500, 0x00}, /* exposure H */ + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */ + {0x3505, 0x80}, /* gain option */ + {0x3508, 0x02}, /* gain H */ + {0x3509, 0x00}, /* gain L */ + {0x350c, 0x00}, /* short gain H */ + {0x350d, 0x80}, /* short gain L */ + {0x3510, 0x00}, /* short exposure H */ + {0x3511, 0x02}, /* short exposure M */ + {0x3512, 0x00}, /* short exposure L */ + {0x3700, 0x18}, + {0x3701, 0x0c}, + {0x3702, 0x28}, + {0x3703, 0x19}, + {0x3704, 0x14}, + {0x3705, 0x00}, + {0x3706, 0x82}, + {0x3707, 0x04}, + {0x3708, 0x24}, + {0x3709, 0x33}, + {0x370a, 0x01}, + {0x370b, 0x82}, + {0x370c, 0x04}, + {0x3718, 0x12}, + {0x3719, 0x31}, + {0x3712, 0x42}, + {0x3714, 0x24}, + {0x371e, 0x19}, + {0x371f, 0x40}, + {0x3720, 0x05}, + {0x3721, 0x05}, + {0x3724, 0x06}, + {0x3725, 0x01}, + {0x3726, 0x06}, + {0x3728, 0x05}, + {0x3729, 0x02}, + {0x372a, 0x03}, + {0x372b, 0x53}, + {0x372c, 0xa3}, + {0x372d, 0x53}, + {0x372e, 0x06}, + {0x372f, 0x10}, + {0x3730, 0x01}, + {0x3731, 0x06}, + {0x3732, 0x14}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x3736, 0x20}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373e, 0x03}, + {0x3750, 0x0a}, + {0x3751, 0x0e}, + {0x3755, 0x10}, + {0x3758, 0x00}, + {0x3759, 0x4c}, + {0x375a, 0x06}, + {0x375b, 0x13}, + {0x375c, 0x20}, + {0x375d, 0x02}, + {0x375e, 0x00}, + {0x375f, 0x14}, + {0x3768, 0x22}, + {0x3769, 0x44}, + {0x376a, 0x44}, + {0x3761, 0x00}, + {0x3762, 0x00}, + {0x3763, 0x00}, + {0x3766, 0xff}, + {0x376b, 0x00}, + {0x3772, 0x23}, + {0x3773, 0x02}, + {0x3774, 0x16}, + {0x3775, 0x12}, + {0x3776, 0x04}, + {0x3777, 0x00}, + {0x3778, 0x17}, + {0x37a0, 0x44}, + {0x37a1, 0x3d}, + {0x37a2, 0x3d}, + {0x37a3, 0x00}, + {0x37a4, 0x00}, + {0x37a5, 0x00}, + {0x37a6, 0x00}, + {0x37a7, 0x44}, + {0x37a8, 0x4c}, + {0x37a9, 0x4c}, + {0x3760, 0x00}, + {0x376f, 0x01}, + {0x37aa, 0x44}, + {0x37ab, 0x2e}, + {0x37ac, 0x2e}, + {0x37ad, 0x33}, + {0x37ae, 0x0d}, + {0x37af, 0x0d}, + {0x37b0, 0x00}, + {0x37b1, 0x00}, + {0x37b2, 0x00}, + {0x37b3, 0x42}, + {0x37b4, 0x42}, + {0x37b5, 0x31}, + {0x37b6, 0x00}, + {0x37b7, 0x00}, + {0x37b8, 0x00}, + {0x37b9, 0xff}, + {0x3800, 0x00}, /* x start H */ + {0x3801, 0x0c}, /* x start L */ + {0x3802, 0x00}, /* y start H */ + {0x3803, 0x0c}, /* y start L */ + {0x3804, 0x0c}, /* x end H */ + {0x3805, 0xd3}, /* x end L */ + {0x3806, 0x09}, /* y end H */ + {0x3807, 0xa3}, /* y end L */ + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3810, 0x00}, /* ISP x win H */ + {0x3811, 0x04}, /* ISP x win L */ + {0x3813, 0x02}, /* ISP y win L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3815, 0x01}, /* x even inc */ + {0x3820, 0x00}, /* vflip off */ + {0x3821, 0x67}, /* mirror on, bin on */ + {0x382a, 0x03}, /* y odd inc */ + {0x382b, 0x01}, /* y even inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x18}, + {0x3841, 0xff}, /* window auto size enable */ + {0x3846, 0x48}, + {0x3d85, 0x16}, /* OTP power up load data enable with BIST */ + {0x3d8c, 0x73}, /* OTP setting start High */ + {0x3d8d, 0xde}, /* OTP setting start Low */ + {0x3f08, 0x08}, + {0x3f0a, 0x00}, + {0x4000, 0xf1}, /* out_range_trig, format_chg_trig */ + {0x4001, 0x10}, /* total 128 black column */ + {0x4005, 0x10}, /* BLC target L */ + {0x4002, 0x27}, /* value used to limit BLC offset */ + {0x4009, 0x81}, /* final BLC offset limitation enable */ + {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */ + {0x401b, 0x00}, /* zero line R coefficient */ + {0x401d, 0x00}, /* zoro line T coefficient */ + {0x4020, 0x00}, /* Anchor left start H */ + {0x4021, 0x04}, /* Anchor left start L */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4024, 0x0f}, /* Anchor right start H */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4026, 0x0f}, /* Anchor right end H */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x4028, 0x00}, /* top zero line start */ + {0x4029, 0x02}, /* top zero line number */ + {0x402a, 0x04}, /* top black line start */ + {0x402b, 0x04}, /* top black line number */ + {0x402c, 0x00}, /* bottom zero line start */ + {0x402d, 0x02}, /* bottom zoro line number */ + {0x402e, 0x04}, /* bottom black line start */ + {0x402f, 0x04}, /* bottom black line number */ + {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */ + {0x4034, 0x3f}, + {0x403d, 0x04}, /* md_precision_en */ + {0x4300, 0xff}, /* clip max H */ + {0x4301, 0x00}, /* clip min H */ + {0x4302, 0x0f}, /* clip min L, clip max L */ + {0x4316, 0x00}, + {0x4500, 0x58}, + {0x4503, 0x18}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x481f, 0x32}, /* clk prepare min */ + {0x4837, 0x16}, /* global timing */ + {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */ + {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */ + {0x4b00, 0x2a}, + {0x4b0d, 0x00}, + {0x4d00, 0x04}, /* temperature sensor */ + {0x4d01, 0x18}, + {0x4d02, 0xc3}, + {0x4d03, 0xff}, + {0x4d04, 0xff}, + {0x4d05, 0xff}, /* temperature sensor */ + {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */ + {0x5001, 0x01}, /* BLC on */ + {0x5002, 0x08}, /* H scale off, WBMATCH off, OTP_DPC */ + {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */ + {0x501e, 0x93}, /* enable digital gain */ + {0x5046, 0x12}, + {0x5780, 0x3e}, /* DPC */ + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x00}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, /* DPC */ + {0x5871, 0x0d}, /* Lenc */ + {0x5870, 0x18}, + {0x586e, 0x10}, + {0x586f, 0x08}, + {0x58f7, 0x01}, + {0x58f8, 0x3d}, /* Lenc */ + {0x5901, 0x00}, /* H skip off, V skip off */ + {0x5b00, 0x02}, /* OTP DPC start address */ + {0x5b01, 0x10}, /* OTP DPC start address */ + {0x5b02, 0x03}, /* OTP DPC end address */ + {0x5b03, 0xcf}, /* OTP DPC end address */ + {0x5b05, 0x6c}, /* recover method = 2b11, */ + {0x5e00, 0x00}, /* use 0x3ff to test pattern off */ + {0x5e01, 0x41}, /* window cut enable */ + {0x382d, 0x7f}, + {0x4825, 0x3a}, /* lpx_p_min */ + {0x4826, 0x40}, /* hs_prepare_min */ + {0x4808, 0x25}, /* wake up delay in 1/1024 s */ + {0x3763, 0x18}, + {0x3768, 0xcc}, + {0x470b, 0x28}, + {0x4202, 0x00}, + {0x400d, 0x10}, /* BLC offset trigger L */ + {0x4040, 0x04}, /* BLC gain th2 */ + {0x403e, 0x04}, /* BLC gain th1 */ + {0x4041, 0xc6}, /* BLC */ + {0x3007, 0x80}, + {0x400a, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 30fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_1632x1224_regs_2lane[] = { + /* + * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz. + * v00_01_00 (05/29/2014) : initial setting + * AM19 : 3617 <- 0xC0 + * AM20 : change FWC_6K_EN to be default 0x3618=0x5a + */ + {0x0100, 0x00}, + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3778, 0x17}, + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3821, 0x67}, /* mirror on, bin on */ + {0x382a, 0x03}, /* y odd inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3f0a, 0x00}, + {0x4001, 0x10}, /* total 128 black column */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x402b, 0x04}, /* top black line number */ + {0x402f, 0x04}, /* bottom black line number */ + {0x4500, 0x58}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x382d, 0x7f}, + {0x0100, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 15fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_3264x2448_regs_2lane[] = { + {0x0100, 0x00}, + {0x3501, 0x9a}, /* exposure M */ + {0x3502, 0x20}, /* exposure L */ + {0x3778, 0x1a}, + {0x3808, 0x0c}, /* x output size H */ + {0x3809, 0xc0}, /* x output size L */ + {0x380a, 0x09}, /* y output size H */ + {0x380b, 0x90}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x94}, /* HTS L */ + {0x380e, 0x09}, /* VTS H */ + {0x380f, 0xaa}, /* VTS L */ + {0x3814, 0x01}, /* x odd inc */ + {0x3821, 0x46}, /* mirror on, bin off */ + {0x382a, 0x01}, /* y odd inc */ + {0x3830, 0x06}, + {0x3836, 0x01}, + {0x3f0a, 0x00}, + {0x4001, 0x00}, /* total 256 black column */ + {0x4022, 0x0c}, /* Anchor left end H */ + {0x4023, 0x60}, /* Anchor left end L */ + {0x4025, 0x36}, /* Anchor right start L */ + {0x4027, 0x37}, /* Anchor right end L */ + {0x402b, 0x08}, /* top black line number */ + {0x402f, 0x08}, /* bottom black line number */ + {0x4500, 0x58}, + {0x4600, 0x01}, + {0x4601, 0x97}, + {0x382d, 0xff}, + {REG_NULL, 0x00}, +}; + +static const struct regval ov8858_global_regs_r2a_4lane[] = { + /* + * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz. + * v00_01_00 (05/29/2014) : initial setting + * AM19 : 3617 <- 0xC0 + * AM20 : change FWC_6K_EN to be default 0x3618=0x5a + */ + {0x0103, 0x01}, /* software reset for OVTATool only */ + {0x0103, 0x01}, /* software reset */ + {0x0100, 0x00}, /* software standby */ + {0x0302, 0x1e}, /* pll1_multi */ + {0x0303, 0x00}, /* pll1_divm */ + {0x0304, 0x03}, /* pll1_div_mipi */ + {0x030e, 0x00}, /* pll2_rdiv */ + {0x030f, 0x04}, /* pll2_divsp */ + {0x0312, 0x01}, /* pll2_pre_div0, pll2_r_divdac */ + {0x031e, 0x0c}, /* pll1_no_lat */ + {0x3600, 0x00}, + {0x3601, 0x00}, + {0x3602, 0x00}, + {0x3603, 0x00}, + {0x3604, 0x22}, + {0x3605, 0x20}, + {0x3606, 0x00}, + {0x3607, 0x20}, + {0x3608, 0x11}, + {0x3609, 0x28}, + {0x360a, 0x00}, + {0x360b, 0x05}, + {0x360c, 0xd4}, + {0x360d, 0x40}, + {0x360e, 0x0c}, + {0x360f, 0x20}, + {0x3610, 0x07}, + {0x3611, 0x20}, + {0x3612, 0x88}, + {0x3613, 0x80}, + {0x3614, 0x58}, + {0x3615, 0x00}, + {0x3616, 0x4a}, + {0x3617, 0x90}, + {0x3618, 0x5a}, + {0x3619, 0x70}, + {0x361a, 0x99}, + {0x361b, 0x0a}, + {0x361c, 0x07}, + {0x361d, 0x00}, + {0x361e, 0x00}, + {0x361f, 0x00}, + {0x3638, 0xff}, + {0x3633, 0x0f}, + {0x3634, 0x0f}, + {0x3635, 0x0f}, + {0x3636, 0x12}, + {0x3645, 0x13}, + {0x3646, 0x83}, + {0x364a, 0x07}, + {0x3015, 0x01}, + {0x3018, 0x72}, /* MIPI 4 lane */ + {0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */ + {0x3022, 0x01}, /* pd_mipi enable when rst_sync */ + {0x3031, 0x0a}, /* MIPI 10-bit mode */ + {0x3034, 0x00}, + {0x3106, 0x01}, /* sclk_div, sclk_pre_div */ + {0x3305, 0xf1}, + {0x3308, 0x00}, + {0x3309, 0x28}, + {0x330a, 0x00}, + {0x330b, 0x20}, + {0x330c, 0x00}, + {0x330d, 0x00}, + {0x330e, 0x00}, + {0x330f, 0x40}, + {0x3307, 0x04}, + {0x3500, 0x00}, /* exposure H */ + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */ + {0x3505, 0x80}, /* gain option */ + {0x3508, 0x02}, /* gain H */ + {0x3509, 0x00}, /* gain L */ + {0x350c, 0x00}, /* short gain H */ + {0x350d, 0x80}, /* short gain L */ + {0x3510, 0x00}, /* short exposure H */ + {0x3511, 0x02}, /* short exposure M */ + {0x3512, 0x00}, /* short exposure L */ + {0x3700, 0x30}, + {0x3701, 0x18}, + {0x3702, 0x50}, + {0x3703, 0x32}, + {0x3704, 0x28}, + {0x3705, 0x00}, + {0x3706, 0x82}, + {0x3707, 0x08}, + {0x3708, 0x48}, + {0x3709, 0x66}, + {0x370a, 0x01}, + {0x370b, 0x82}, + {0x370c, 0x07}, + {0x3718, 0x14}, + {0x3719, 0x31}, + {0x3712, 0x44}, + {0x3714, 0x24}, + {0x371e, 0x31}, + {0x371f, 0x7f}, + {0x3720, 0x0a}, + {0x3721, 0x0a}, + {0x3724, 0x0c}, + {0x3725, 0x02}, + {0x3726, 0x0c}, + {0x3728, 0x0a}, + {0x3729, 0x03}, + {0x372a, 0x06}, + {0x372b, 0xa6}, + {0x372c, 0xa6}, + {0x372d, 0xa6}, + {0x372e, 0x0c}, + {0x372f, 0x20}, + {0x3730, 0x02}, + {0x3731, 0x0c}, + {0x3732, 0x28}, + {0x3733, 0x10}, + {0x3734, 0x40}, + {0x3736, 0x30}, + {0x373a, 0x0a}, + {0x373b, 0x0b}, + {0x373c, 0x14}, + {0x373e, 0x06}, + {0x3750, 0x0a}, + {0x3751, 0x0e}, + {0x3755, 0x10}, + {0x3758, 0x00}, + {0x3759, 0x4c}, + {0x375a, 0x0c}, + {0x375b, 0x26}, + {0x375c, 0x20}, + {0x375d, 0x04}, + {0x375e, 0x00}, + {0x375f, 0x28}, + {0x3768, 0x22}, + {0x3769, 0x44}, + {0x376a, 0x44}, + {0x3761, 0x00}, + {0x3762, 0x00}, + {0x3763, 0x00}, + {0x3766, 0xff}, + {0x376b, 0x00}, + {0x3772, 0x46}, + {0x3773, 0x04}, + {0x3774, 0x2c}, + {0x3775, 0x13}, + {0x3776, 0x08}, + {0x3777, 0x00}, + {0x3778, 0x17}, + {0x37a0, 0x88}, + {0x37a1, 0x7a}, + {0x37a2, 0x7a}, + {0x37a3, 0x00}, + {0x37a4, 0x00}, + {0x37a5, 0x00}, + {0x37a6, 0x00}, + {0x37a7, 0x88}, + {0x37a8, 0x98}, + {0x37a9, 0x98}, + {0x3760, 0x00}, + {0x376f, 0x01}, + {0x37aa, 0x88}, + {0x37ab, 0x5c}, + {0x37ac, 0x5c}, + {0x37ad, 0x55}, + {0x37ae, 0x19}, + {0x37af, 0x19}, + {0x37b0, 0x00}, + {0x37b1, 0x00}, + {0x37b2, 0x00}, + {0x37b3, 0x84}, + {0x37b4, 0x84}, + {0x37b5, 0x60}, + {0x37b6, 0x00}, + {0x37b7, 0x00}, + {0x37b8, 0x00}, + {0x37b9, 0xff}, + {0x3800, 0x00}, /* x start H */ + {0x3801, 0x0c}, /* x start L */ + {0x3802, 0x00}, /* y start H */ + {0x3803, 0x0c}, /* y start L */ + {0x3804, 0x0c}, /* x end H */ + {0x3805, 0xd3}, /* x end L */ + {0x3806, 0x09}, /* y end H */ + {0x3807, 0xa3}, /* y end L */ + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3810, 0x00}, /* ISP x win H */ + {0x3811, 0x04}, /* ISP x win L */ + {0x3813, 0x02}, /* ISP y win L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3815, 0x01}, /* x even inc */ + {0x3820, 0x00}, /* vflip off */ + {0x3821, 0x67}, /* mirror on, bin o */ + {0x382a, 0x03}, /* y odd inc */ + {0x382b, 0x01}, /* y even inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x18}, + {0x3841, 0xff}, /* window auto size enable */ + {0x3846, 0x48}, + {0x3d85, 0x16}, /* OTP power up load data/setting enable */ + {0x3d8c, 0x73}, /* OTP setting start High */ + {0x3d8d, 0xde}, /* OTP setting start Low */ + {0x3f08, 0x10}, + {0x3f0a, 0x00}, + {0x4000, 0xf1}, /* out_range/format_chg/gain/exp_chg trig enable */ + {0x4001, 0x10}, /* total 128 black column */ + {0x4005, 0x10}, /* BLC target L */ + {0x4002, 0x27}, /* value used to limit BLC offset */ + {0x4009, 0x81}, /* final BLC offset limitation enable */ + {0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */ + {0x401b, 0x00}, /* zero line R coefficient */ + {0x401d, 0x00}, /* zoro line T coefficient */ + {0x4020, 0x00}, /* Anchor left start H */ + {0x4021, 0x04}, /* Anchor left start L */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4024, 0x0f}, /* Anchor right start H */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4026, 0x0f}, /* Anchor right end H */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x4028, 0x00}, /* top zero line start */ + {0x4029, 0x02}, /* top zero line number */ + {0x402a, 0x04}, /* top black line start */ + {0x402b, 0x04}, /* top black line number */ + {0x402c, 0x00}, /* bottom zero line start */ + {0x402d, 0x02}, /* bottom zoro line number */ + {0x402e, 0x04}, /* bottom black line start */ + {0x402f, 0x04}, /* bottom black line number */ + {0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */ + {0x4034, 0x3f}, + {0x403d, 0x04}, /* md_precision_en */ + {0x4300, 0xff}, /* clip max H */ + {0x4301, 0x00}, /* clip min H */ + {0x4302, 0x0f}, /* clip min L, clip max L */ + {0x4316, 0x00}, + {0x4500, 0x58}, + {0x4503, 0x18}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x481f, 0x32}, /* clk prepare min */ + {0x4837, 0x16}, /* global timing */ + {0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */ + {0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */ + {0x4b00, 0x2a}, + {0x4b0d, 0x00}, + {0x4d00, 0x04}, /* temperature sensor */ + {0x4d01, 0x18}, + {0x4d02, 0xc3}, + {0x4d03, 0xff}, + {0x4d04, 0xff}, + {0x4d05, 0xff}, /* temperature sensor */ + {0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */ + {0x5001, 0x01}, /* BLC on */ + {0x5002, 0x08}, /* WBMATCH sensor's gain, H scale/WBMATCH/OTP_DPC off */ + {0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */ + {0x501e, 0x93}, /* enable digital gain */ + {0x5046, 0x12}, + {0x5780, 0x3e}, /* DPC */ + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x00}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, /* DPC */ + {0x5871, 0x0d}, /* Lenc */ + {0x5870, 0x18}, + {0x586e, 0x10}, + {0x586f, 0x08}, + {0x58f7, 0x01}, + {0x58f8, 0x3d}, /* Lenc */ + {0x5901, 0x00}, /* H skip off, V skip off */ + {0x5b00, 0x02}, /* OTP DPC start address */ + {0x5b01, 0x10}, /* OTP DPC start address */ + {0x5b02, 0x03}, /* OTP DPC end address */ + {0x5b03, 0xcf}, /* OTP DPC end address */ + {0x5b05, 0x6c}, /* recover method = 2b11 */ + {0x5e00, 0x00}, /* use 0x3ff to test pattern off */ + {0x5e01, 0x41}, /* window cut enable */ + {0x382d, 0x7f}, + {0x4825, 0x3a}, /* lpx_p_min */ + {0x4826, 0x40}, /* hs_prepare_min */ + {0x4808, 0x25}, /* wake up delay in 1/1024 s */ + {0x3763, 0x18}, + {0x3768, 0xcc}, + {0x470b, 0x28}, + {0x4202, 0x00}, + {0x400d, 0x10}, /* BLC offset trigger L */ + {0x4040, 0x04}, /* BLC gain th2 */ + {0x403e, 0x04}, /* BLC gain th1 */ + {0x4041, 0xc6}, /* BLC */ + {0x3007, 0x80}, + {0x400a, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 60fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_1632x1224_regs_4lane[] = { + {0x0100, 0x00}, + {0x3501, 0x4d}, /* exposure M */ + {0x3502, 0x40}, /* exposure L */ + {0x3808, 0x06}, /* x output size H */ + {0x3809, 0x60}, /* x output size L */ + {0x380a, 0x04}, /* y output size H */ + {0x380b, 0xc8}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x88}, /* HTS L */ + {0x380e, 0x04}, /* VTS H */ + {0x380f, 0xdc}, /* VTS L */ + {0x3814, 0x03}, /* x odd inc */ + {0x3821, 0x67}, /* mirror on, bin on */ + {0x382a, 0x03}, /* y odd inc */ + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3f0a, 0x00}, + {0x4001, 0x10}, /* total 128 black column */ + {0x4022, 0x06}, /* Anchor left end H */ + {0x4023, 0x00}, /* Anchor left end L */ + {0x4025, 0x2a}, /* Anchor right start L */ + {0x4027, 0x2b}, /* Anchor right end L */ + {0x402b, 0x04}, /* top black line number */ + {0x402f, 0x04}, /* bottom black line number */ + {0x4500, 0x58}, + {0x4600, 0x00}, + {0x4601, 0xcb}, + {0x382d, 0x7f}, + {0x0100, 0x01}, + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 30fps + * mipi_datarate per lane 720Mbps + */ +static const struct regval ov8858_3264x2448_regs_4lane[] = { + {0x0100, 0x00}, + {0x3501, 0x9a}, /* exposure M */ + {0x3502, 0x20}, /* exposure L */ + {0x3808, 0x0c}, /* x output size H */ + {0x3809, 0xc0}, /* x output size L */ + {0x380a, 0x09}, /* y output size H */ + {0x380b, 0x90}, /* y output size L */ + {0x380c, 0x07}, /* HTS H */ + {0x380d, 0x94}, /* HTS L */ + {0x380e, 0x09}, /* VTS H */ + {0x380f, 0xaa}, /* VTS L */ + {0x3814, 0x01}, /* x odd inc */ + {0x3821, 0x46}, /* mirror on, bin off */ + {0x382a, 0x01}, /* y odd inc */ + {0x3830, 0x06}, + {0x3836, 0x01}, + {0x3f0a, 0x00}, + {0x4001, 0x00}, /* total 256 black column */ + {0x4022, 0x0c}, /* Anchor left end H */ + {0x4023, 0x60}, /* Anchor left end L */ + {0x4025, 0x36}, /* Anchor right start L */ + {0x4027, 0x37}, /* Anchor right end L */ + {0x402b, 0x08}, /* top black line number */ + {0x402f, 0x08}, /* interpolation x/y disable, Anchor one disable */ + {0x4500, 0x58}, + {0x4600, 0x01}, + {0x4601, 0x97}, + {0x382d, 0xff}, + {REG_NULL, 0x00}, +}; + +static const struct ov8858_mode ov8858_modes[] = { + { + .width = 3264, + .height = 2448, + .exp_def = 2464, + .hts_def = 1940 * 2, + .vts_def = 2472, + .reg_modes = { + .mode_2lanes = ov8858_3264x2448_regs_2lane, + .mode_4lanes = ov8858_3264x2448_regs_4lane, + }, + }, + { + .width = 1632, + .height = 1224, + .exp_def = 1232, + .hts_def = 1928 * 2, + .vts_def = 1244, + .reg_modes = { + .mode_2lanes = ov8858_1632x1224_regs_2lane, + .mode_4lanes = ov8858_1632x1224_regs_4lane, + }, + }, +}; + +static const s64 link_freq_menu_items[] = { + OV8858_LINK_FREQ +}; + +static const char * const ov8858_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", + "Vertical Color Bar Type 2", + "Vertical Color Bar Type 3", + "Vertical Color Bar Type 4" +}; + +/* ---------------------------------------------------------------------------- + * HW access + */ + +static int ov8858_write(struct ov8858 *ov8858, u32 reg, u32 val, int *err) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3; + u16 addr = reg & OV8858_REG_ADDR_MASK; + u8 buf[6]; + int ret; + + if (err && *err) + return *err; + + put_unaligned_be16(addr, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + + ret = i2c_master_send(client, buf, len + 2); + if (ret != len + 2) { + ret = ret < 0 ? ret : -EIO; + if (err) + *err = ret; + + dev_err(&client->dev, + "Failed to write reg %u: %d\n", addr, ret); + return ret; + } + + return 0; +} + +static int ov8858_write_array(struct ov8858 *ov8858, const struct regval *regs) +{ + unsigned int i; + int ret = 0; + + for (i = 0; ret == 0 && regs[i].addr != REG_NULL; ++i) { + ov8858_write(ov8858, OV8858_REG_8BIT(regs[i].addr), + regs[i].val, &ret); + } + + return ret; +} + +static int ov8858_read(struct ov8858 *ov8858, u32 reg, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + __be16 reg_addr_be = cpu_to_be16(reg & OV8858_REG_ADDR_MASK); + unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3; + struct i2c_msg msgs[2]; + __be32 data_be = 0; + u8 *data_be_p; + int ret; + + data_be_p = (u8 *)&data_be; + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + ret = ret < 0 ? ret : -EIO; + dev_err(&client->dev, + "Failed to read reg %u: %d\n", reg, ret); + return ret; + } + + *val = be32_to_cpu(data_be); + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Streaming + */ + +static int ov8858_start_stream(struct ov8858 *ov8858, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + const struct ov8858_mode *mode; + const struct regval *reg_list; + int ret; + + ret = ov8858_write_array(ov8858, ov8858->global_regs); + if (ret) + return ret; + + format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0); + mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes), + width, height, format->width, + format->height); + + reg_list = ov8858->num_lanes == 4 + ? mode->reg_modes.mode_4lanes + : mode->reg_modes.mode_2lanes; + + ret = ov8858_write_array(ov8858, reg_list); + if (ret) + return ret; + + /* 200 usec max to let PLL stabilize. */ + fsleep(200); + + ret = __v4l2_ctrl_handler_setup(&ov8858->ctrl_handler); + if (ret) + return ret; + + ret = ov8858_write(ov8858, OV8858_REG_SC_CTRL0100, + OV8858_MODE_STREAMING, NULL); + if (ret) + return ret; + + /* t5 (fixed) = 10msec before entering streaming state */ + fsleep(10000); + + return 0; +} + +static int ov8858_stop_stream(struct ov8858 *ov8858) +{ + return ov8858_write(ov8858, OV8858_REG_SC_CTRL0100, + OV8858_MODE_SW_STANDBY, NULL); +} + +static int ov8858_s_stream(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + struct v4l2_subdev_state *state; + int ret = 0; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (on) { + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + goto unlock_and_return; + + ret = ov8858_start_stream(ov8858, state); + if (ret) { + dev_err(&client->dev, "Failed to start streaming\n"); + pm_runtime_put_sync(&client->dev); + goto unlock_and_return; + } + } else { + ov8858_stop_stream(ov8858); + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } + +unlock_and_return: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static const struct v4l2_subdev_video_ops ov8858_video_ops = { + .s_stream = ov8858_s_stream, +}; + +/* ---------------------------------------------------------------------------- + * Pad ops + */ + +static int ov8858_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct ov8858 *ov8858 = sd_to_ov8858(sd); + const struct ov8858_mode *mode; + s64 h_blank, vblank_def; + + mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes), + width, height, fmt->format.width, + fmt->format.height); + + fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; + + /* Store the format in the current subdev state. */ + *v4l2_subdev_get_pad_format(sd, state, 0) = fmt->format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + /* Adjust control limits when a new mode is applied. */ + h_blank = mode->hts_def - mode->width; + __v4l2_ctrl_modify_range(ov8858->hblank, h_blank, h_blank, 1, + h_blank); + + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov8858->vblank, vblank_def, + OV8858_VTS_MAX - mode->height, 1, + vblank_def); + + return 0; +} + +static int ov8858_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(ov8858_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10) + return -EINVAL; + + fse->min_width = ov8858_modes[fse->index].width; + fse->max_width = ov8858_modes[fse->index].width; + fse->max_height = ov8858_modes[fse->index].height; + fse->min_height = ov8858_modes[fse->index].height; + + return 0; +} + +static int ov8858_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov8858_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + const struct ov8858_mode *def_mode = &ov8858_modes[0]; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .width = def_mode->width, + .height = def_mode->height, + }, + }; + + ov8858_set_fmt(sd, sd_state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_pad_ops ov8858_pad_ops = { + .init_cfg = ov8858_init_cfg, + .enum_mbus_code = ov8858_enum_mbus_code, + .enum_frame_size = ov8858_enum_frame_sizes, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ov8858_set_fmt, +}; + +static const struct v4l2_subdev_core_ops ov8858_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops ov8858_subdev_ops = { + .core = &ov8858_core_ops, + .video = &ov8858_video_ops, + .pad = &ov8858_pad_ops, +}; + +/* ---------------------------------------------------------------------------- + * Controls handling + */ + +static int ov8858_enable_test_pattern(struct ov8858 *ov8858, u32 pattern) +{ + u32 val; + + if (pattern) + val = (pattern - 1) | OV8858_TEST_PATTERN_ENABLE; + else + val = OV8858_TEST_PATTERN_DISABLE; + + return ov8858_write(ov8858, OV8858_REG_TEST_PATTERN, val, NULL); +} + +static int ov8858_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov8858 *ov8858 = container_of(ctrl->handler, + struct ov8858, ctrl_handler); + + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + u16 digi_gain; + s64 max_exp; + int ret; + + /* + * The control handler and the subdev state use the same mutex and the + * mutex is guaranteed to be locked: + * - by the core when s_ctrl is called int the VIDIOC_S_CTRL call path + * - by the driver when s_ctrl is called in the s_stream(1) call path + */ + state = v4l2_subdev_get_locked_active_state(&ov8858->subdev); + format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0); + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max_exp = format->height + ctrl->val - OV8858_EXPOSURE_MARGIN; + __v4l2_ctrl_modify_range(ov8858->exposure, + ov8858->exposure->minimum, max_exp, + ov8858->exposure->step, + ov8858->exposure->default_value); + break; + } + + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + /* 4 least significant bits of exposure are fractional part */ + ret = ov8858_write(ov8858, OV8858_REG_LONG_EXPO, + ctrl->val << 4, NULL); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov8858_write(ov8858, OV8858_REG_LONG_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_DIGITAL_GAIN: + /* + * Digital gain is assembled as: + * 0x350a[7:0] = dgain[13:6] + * 0x350b[5:0] = dgain[5:0] + * Reassemble the control value to write it in one go. + */ + digi_gain = (ctrl->val & OV8858_LONG_DIGIGAIN_L_MASK) + | ((ctrl->val & OV8858_LONG_DIGIGAIN_H_MASK) << + OV8858_LONG_DIGIGAIN_H_SHIFT); + ret = ov8858_write(ov8858, OV8858_REG_LONG_DIGIGAIN, + digi_gain, NULL); + break; + case V4L2_CID_VBLANK: + ret = ov8858_write(ov8858, OV8858_REG_VTS, + ctrl->val + format->height, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov8858_enable_test_pattern(ov8858, ctrl->val); + break; + default: + ret = -EINVAL; + dev_warn(&client->dev, "%s Unhandled id: 0x%x\n", + __func__, ctrl->id); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov8858_ctrl_ops = { + .s_ctrl = ov8858_set_ctrl, +}; + +/* ---------------------------------------------------------------------------- + * Power Management + */ + +static int ov8858_power_on(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct device *dev = &client->dev; + unsigned long delay_us; + int ret; + + if (clk_get_rate(ov8858->xvclk) != OV8858_XVCLK_FREQ) + dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); + + ret = clk_prepare_enable(ov8858->xvclk); + if (ret < 0) { + dev_err(dev, "Failed to enable xvclk\n"); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(ov8858_supply_names), + ov8858->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto disable_clk; + } + + /* + * The chip manual only suggests 8192 cycles prior to first SCCB + * transaction, but a double sleep between the release of gpios + * helps with sporadic failures observed at probe time. + */ + delay_us = DIV_ROUND_UP(8192, OV8858_XVCLK_FREQ / 1000 / 1000); + + gpiod_set_value_cansleep(ov8858->reset_gpio, 0); + fsleep(delay_us); + gpiod_set_value_cansleep(ov8858->pwdn_gpio, 0); + fsleep(delay_us); + + return 0; + +disable_clk: + clk_disable_unprepare(ov8858->xvclk); + + return ret; +} + +static void ov8858_power_off(struct ov8858 *ov8858) +{ + gpiod_set_value_cansleep(ov8858->pwdn_gpio, 1); + clk_disable_unprepare(ov8858->xvclk); + gpiod_set_value_cansleep(ov8858->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(ov8858_supply_names), + ov8858->supplies); +} + +static int ov8858_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + + return ov8858_power_on(ov8858); +} + +static int ov8858_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + + ov8858_power_off(ov8858); + + return 0; +} + +static const struct dev_pm_ops ov8858_pm_ops = { + SET_RUNTIME_PM_OPS(ov8858_runtime_suspend, + ov8858_runtime_resume, NULL) +}; + +/* ---------------------------------------------------------------------------- + * Probe and initialization + */ + +static int ov8858_init_ctrls(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct v4l2_ctrl_handler *handler = &ov8858->ctrl_handler; + const struct ov8858_mode *mode = &ov8858_modes[0]; + struct v4l2_fwnode_device_properties props; + s64 exposure_max, vblank_def; + unsigned int pixel_rate; + struct v4l2_ctrl *ctrl; + u32 h_blank; + int ret; + + ret = v4l2_ctrl_handler_init(handler, 10); + if (ret) + return ret; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* pixel rate = link frequency * 2 * lanes / bpp */ + pixel_rate = OV8858_LINK_FREQ * 2 * ov8858->num_lanes / 10; + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts_def - mode->width; + ov8858->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ov8858->hblank) + ov8858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank_def = mode->vts_def - mode->height; + ov8858->vblank = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + OV8858_VTS_MAX - mode->height, + 1, vblank_def); + + exposure_max = mode->vts_def - OV8858_EXPOSURE_MARGIN; + ov8858->exposure = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, + V4L2_CID_EXPOSURE, + OV8858_EXPOSURE_MIN, + exposure_max, OV8858_EXPOSURE_STEP, + mode->exp_def); + + v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV8858_LONG_GAIN_MIN, OV8858_LONG_GAIN_MAX, + OV8858_LONG_GAIN_STEP, OV8858_LONG_GAIN_DEFAULT); + + v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV8858_LONG_DIGIGAIN_MIN, OV8858_LONG_DIGIGAIN_MAX, + OV8858_LONG_DIGIGAIN_STEP, + OV8858_LONG_DIGIGAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(handler, &ov8858_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov8858_test_pattern_menu) - 1, + 0, 0, ov8858_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + goto err_free_handler; + } + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto err_free_handler; + + ret = v4l2_ctrl_new_fwnode_properties(handler, &ov8858_ctrl_ops, + &props); + if (ret) + goto err_free_handler; + + ov8858->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + dev_err(&client->dev, "Failed to init controls: %d\n", ret); + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int ov8858_check_sensor_id(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + u32 id = 0; + int ret; + + ret = ov8858_read(ov8858, OV8858_REG_CHIP_ID, &id); + if (ret) + return ret; + + if (id != OV8858_CHIP_ID) { + dev_err(&client->dev, "Unexpected sensor id 0x%x\n", id); + return -ENODEV; + } + + ret = ov8858_read(ov8858, OV8858_REG_SUB_ID, &id); + if (ret) + return ret; + + dev_info(&client->dev, "Detected OV8858 sensor, revision 0x%x\n", id); + + if (id == OV8858_R2A) { + /* R2A supports 2 and 4 lanes modes. */ + ov8858->global_regs = ov8858->num_lanes == 4 + ? ov8858_global_regs_r2a_4lane + : ov8858_global_regs_r2a_2lane; + } else if (ov8858->num_lanes == 2) { + /* + * R1A only supports 2 lanes mode and it's only partially + * supported. + */ + ov8858->global_regs = ov8858_global_regs_r1a; + dev_warn(&client->dev, "R1A may not work well!\n"); + } else { + dev_err(&client->dev, + "Unsupported number of data lanes for R1A revision.\n"); + return -EINVAL; + } + + return 0; +} + +static int ov8858_configure_regulators(struct ov8858 *ov8858) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov8858_supply_names); i++) + ov8858->supplies[i].supply = ov8858_supply_names[i]; + + return devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(ov8858_supply_names), + ov8858->supplies); +} + +static int ov8858_parse_of(struct ov8858 *ov8858) +{ + struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev); + struct device *dev = &client->dev; + struct fwnode_handle *endpoint; + int ret; + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + if (!endpoint) { + dev_err(dev, "Failed to get endpoint\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_parse(endpoint, &vep); + if (ret) { + dev_err(dev, "Failed to parse endpoint: %d\n", ret); + fwnode_handle_put(endpoint); + return ret; + } + + ov8858->num_lanes = vep.bus.mipi_csi2.num_data_lanes; + switch (ov8858->num_lanes) { + case 4: + case 2: + break; + default: + dev_err(dev, "Unsupported number of data lanes %u\n", + ov8858->num_lanes); + fwnode_handle_put(endpoint); + return -EINVAL; + } + + ov8858->subdev.fwnode = endpoint; + + return 0; +} + +static int ov8858_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct v4l2_subdev *sd; + struct ov8858 *ov8858; + int ret; + + ov8858 = devm_kzalloc(dev, sizeof(*ov8858), GFP_KERNEL); + if (!ov8858) + return -ENOMEM; + + ov8858->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(ov8858->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov8858->xvclk), + "Failed to get xvclk\n"); + + ov8858->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov8858->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ov8858->reset_gpio), + "Failed to get reset gpio\n"); + + ov8858->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ov8858->pwdn_gpio)) + return dev_err_probe(dev, PTR_ERR(ov8858->pwdn_gpio), + "Failed to get powerdown gpio\n"); + + v4l2_i2c_subdev_init(&ov8858->subdev, client, &ov8858_subdev_ops); + + ret = ov8858_configure_regulators(ov8858); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ret = ov8858_parse_of(ov8858); + if (ret) + return ret; + + ret = ov8858_init_ctrls(ov8858); + if (ret) + goto err_put_fwnode; + + sd = &ov8858->subdev; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + ov8858->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad); + if (ret < 0) + goto err_free_handler; + + sd->state_lock = ov8858->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) { + dev_err(&client->dev, "Subdev initialization error %d\n", ret); + goto err_clean_entity; + } + + ret = ov8858_power_on(ov8858); + if (ret) + goto err_clean_entity; + + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + + ret = ov8858_check_sensor_id(ov8858); + if (ret) + goto err_power_off; + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + ret = v4l2_async_register_subdev_sensor(sd); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_power_off; + } + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; + +err_power_off: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + ov8858_power_off(ov8858); +err_clean_entity: + media_entity_cleanup(&sd->entity); +err_free_handler: + v4l2_ctrl_handler_free(&ov8858->ctrl_handler); +err_put_fwnode: + fwnode_handle_put(ov8858->subdev.fwnode); + + return ret; +} + +static void ov8858_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8858 *ov8858 = sd_to_ov8858(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(&ov8858->ctrl_handler); + fwnode_handle_put(ov8858->subdev.fwnode); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov8858_power_off(ov8858); + pm_runtime_set_suspended(&client->dev); +} + +static const struct of_device_id ov8858_of_match[] = { + { .compatible = "ovti,ov8858" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov8858_of_match); + +static struct i2c_driver ov8858_i2c_driver = { + .driver = { + .name = "ov8858", + .pm = &ov8858_pm_ops, + .of_match_table = ov8858_of_match, + }, + .probe_new = &ov8858_probe, + .remove = &ov8858_remove, +}; + +module_i2c_driver(ov8858_i2c_driver); + +MODULE_DESCRIPTION("OmniVision OV8858 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 37a55d53af56..7f46cac38aab 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -148,7 +148,6 @@ struct ov9282_mode { /** * struct ov9282 - ov9282 sensor device structure * @dev: Pointer to generic device - * @client: Pointer to i2c client * @sd: V4L2 sub-device * @pad: Media pad. Only one pad supported * @reset_gpio: Sensor reset gpio @@ -170,7 +169,6 @@ struct ov9282_mode { */ struct ov9282 { struct device *dev; - struct i2c_client *client; struct v4l2_subdev sd; struct media_pad pad; struct gpio_desc *reset_gpio; @@ -1144,10 +1142,9 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282) } ret = ov9282_configure_regulators(ov9282); - if (ret) { - dev_err(ov9282->dev, "Failed to get power regulators\n"); - return ret; - } + if (ret) + return dev_err_probe(ov9282->dev, ret, + "Failed to get power regulators\n"); rate = clk_get_rate(ov9282->inclk); if (rate != OV9282_INCLK_RATE) { diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 59b03b0860d5..7938a3327d3e 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -26,7 +26,6 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> -#include <media/i2c/s5c73m3.h> #include <media/v4l2-fwnode.h> #include "s5c73m3.h" @@ -436,7 +435,7 @@ static int __s5c73m3_s_stream(struct s5c73m3 *state, struct v4l2_subdev *sd, state->streaming = !!on; if (!on) - return ret; + return 0; if (state->apply_fiv) { ret = s5c73m3_set_frame_rate(state); @@ -1522,25 +1521,16 @@ static const struct v4l2_subdev_ops oif_subdev_ops = { .video = &s5c73m3_oif_video_ops, }; -static int s5c73m3_get_platform_data(struct s5c73m3 *state) +static int s5c73m3_get_dt_data(struct s5c73m3 *state) { - struct i2c_client *c = state->i2c_client; - struct device *dev = &c->dev; - const struct s5c73m3_platform_data *pdata = dev->platform_data; + struct device *dev = &state->i2c_client->dev; struct device_node *node = dev->of_node; struct device_node *node_ep; struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; int ret; - if (!node) { - if (!pdata) { - dev_err(dev, "Platform data not specified\n"); - return -EINVAL; - } - - state->mclk_frequency = pdata->mclk_frequency; - return 0; - } + if (!node) + return -EINVAL; state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME); if (IS_ERR(state->clock)) @@ -1603,7 +1593,7 @@ static int s5c73m3_probe(struct i2c_client *client) return -ENOMEM; state->i2c_client = client; - ret = s5c73m3_get_platform_data(state); + ret = s5c73m3_get_dt_data(state); if (ret < 0) return ret; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c index e3543ae384ed..1c8103670fa2 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c @@ -23,7 +23,6 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> -#include <media/i2c/s5c73m3.h> #include "s5c73m3.h" diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h index 1fc7df41c5ee..627e80cf5b72 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3.h +++ b/drivers/media/i2c/s5c73m3/s5c73m3.h @@ -16,7 +16,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> -#include <media/i2c/s5c73m3.h> #define DRIVER_NAME "S5C73M3" diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 86e70a980218..efeda3956f81 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1804,9 +1804,9 @@ static int saa711x_detect_chip(struct i2c_client *client, return -ENODEV; } -static int saa711x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int saa711x_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct saa711x_state *state; struct v4l2_subdev *sd; struct v4l2_ctrl_handler *hdl; @@ -1951,7 +1951,7 @@ static struct i2c_driver saa711x_driver = { .driver = { .name = "saa7115", }, - .probe = saa711x_probe, + .probe_new = saa711x_probe, .remove = saa711x_remove, .id_table = saa711x_id, }; diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index 78c9388c2ea1..f98f3a1c38a9 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -708,9 +708,9 @@ static const struct v4l2_subdev_ops saa7127_ops = { /* ----------------------------------------------------------------------- */ -static int saa7127_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int saa7127_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct saa7127_state *state; struct v4l2_subdev *sd; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ @@ -810,7 +810,7 @@ static struct i2c_driver saa7127_driver = { .driver = { .name = "saa7127", }, - .probe = saa7127_probe, + .probe_new = saa7127_probe, .remove = saa7127_remove, .id_table = saa7127_id, }; diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index 826baf4e064d..5dcabee6677d 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -5,7 +5,6 @@ * Copyright (C) 2022 STMicroelectronics SA */ -#include <asm-generic/unaligned.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> @@ -15,6 +14,9 @@ #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/units.h> + +#include <asm/unaligned.h> + #include <media/mipi-csi2.h> #include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index d1f552bd81d4..4063754a6732 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -406,7 +406,7 @@ tc358746_apply_pll_config(struct tc358746 *tc358746) val = PLL_FRS(ilog2(post)) | RESETB | PLL_EN; mask = PLL_FRS_MASK | RESETB | PLL_EN; - tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val); + err = tc358746_update_bits(tc358746, PLLCTL1_REG, mask, val); if (err) return err; @@ -988,6 +988,8 @@ static int __maybe_unused tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { struct tc358746 *tc358746 = to_tc358746(sd); + u32 val; + int err; /* 32-bit registers starting from CLW_DPHYCONTTX */ reg->size = reg->reg < CLW_DPHYCONTTX_REG ? 2 : 4; @@ -995,12 +997,13 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) if (!pm_runtime_get_if_in_use(sd->dev)) return 0; - tc358746_read(tc358746, reg->reg, (u32 *)®->val); + err = tc358746_read(tc358746, reg->reg, &val); + reg->val = val; pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); - return 0; + return err; } static int __maybe_unused diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 83931826cf6f..27f6393dc327 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2519,9 +2519,9 @@ static struct snd_soc_component_driver tda1997x_codec_driver = { .endianness = 1, }; -static int tda1997x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tda1997x_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct tda1997x_state *state; struct tda1997x_platform_data *pdata; struct v4l2_subdev *sd; @@ -2834,7 +2834,7 @@ static struct i2c_driver tda1997x_i2c_driver = { .name = "tda1997x", .of_match_table = of_match_ptr(tda1997x_of_id), }, - .probe = tda1997x_probe, + .probe_new = tda1997x_probe, .remove = tda1997x_remove, .id_table = tda1997x_i2c_id, }; diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 9f1ed078b661..a54c76d9e23b 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1934,8 +1934,9 @@ static const struct v4l2_subdev_ops tvaudio_ops = { /* i2c registration */ -static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int tvaudio_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct CHIPSTATE *chip; struct CHIPDESC *desc; struct v4l2_subdev *sd; @@ -2094,7 +2095,7 @@ static struct i2c_driver tvaudio_driver = { .driver = { .name = "tvaudio", }, - .probe = tvaudio_probe, + .probe_new = tvaudio_probe, .remove = tvaudio_remove, .id_table = tvaudio_id, }; diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index a746d96875f9..f294cae72b01 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -1017,14 +1017,14 @@ done: /** * tvp514x_probe() - decoder driver i2c probe handler * @client: i2c driver client device structure - * @id: i2c driver id table * * Register decoder as an i2c client device and V4L2 * device. */ static int -tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) +tvp514x_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct tvp514x_platform_data *pdata = tvp514x_get_pdata(client); struct tvp514x_decoder *decoder; struct v4l2_subdev *sd; @@ -1208,7 +1208,7 @@ static struct i2c_driver tvp514x_driver = { .of_match_table = of_match_ptr(tvp514x_of_match), .name = TVP514X_MODULE_NAME, }, - .probe = tvp514x_probe, + .probe_new = tvp514x_probe, .remove = tvp514x_remove, .id_table = tvp514x_id, }; diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index f15ef2d13059..dddf9827b314 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -757,9 +757,9 @@ static void video_i2c_release(struct video_device *vdev) kfree(data); } -static int video_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int video_i2c_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct video_i2c_data *data; struct v4l2_device *v4l2_dev; struct vb2_queue *queue; @@ -959,7 +959,7 @@ static struct i2c_driver video_i2c_driver = { .of_match_table = video_i2c_of_match, .pm = &video_i2c_pm_ops, }, - .probe = video_i2c_probe, + .probe_new = video_i2c_probe, .remove = video_i2c_remove, .id_table = video_i2c_id_table, }; diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index b8bcbc734eaf..e7216a985ba6 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -226,7 +226,13 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init); * Graph traversal */ -/* +/** + * media_entity_has_pad_interdep - Check interdependency between two pads + * + * @entity: The entity + * @pad0: The first pad index + * @pad1: The second pad index + * * This function checks the interdependency inside the entity between @pad0 * and @pad1. If two pads are interdependent they are part of the same pipeline * and enabling one of the pads means that the other pad will become "locked" @@ -236,6 +242,13 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init); * to check the dependency inside the entity between @pad0 and @pad1. If the * has_pad_interdep operation is not implemented, all pads of the entity are * considered to be interdependent. + * + * One of @pad0 and @pad1 must be a sink pad and the other one a source pad. + * The function returns false if both pads are sinks or sources. + * + * The caller must hold entity->graph_obj.mdev->mutex. + * + * Return: true if the pads are connected internally and false otherwise. */ static bool media_entity_has_pad_interdep(struct media_entity *entity, unsigned int pad0, unsigned int pad1) @@ -295,7 +308,7 @@ static struct media_entity *stack_pop(struct media_graph *graph) * * Reserve resources for graph walk in media device's current * state. The memory must be released using - * media_graph_walk_free(). + * media_graph_walk_cleanup(). * * Returns error on failure, zero on success. */ @@ -703,7 +716,7 @@ done: __must_check int __media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; struct media_pipeline_pad *err_ppad; struct media_pipeline_pad *ppad; int ret; @@ -711,8 +724,8 @@ __must_check int __media_pipeline_start(struct media_pad *pad, lockdep_assert_held(&mdev->graph_mutex); /* - * If the entity is already part of a pipeline, that pipeline must - * be the same as the pipe given to media_pipeline_start(). + * If the pad is already part of a pipeline, that pipeline must be the + * same as the pipe given to media_pipeline_start(). */ if (WARN_ON(pad->pipe && pad->pipe != pipe)) return -EINVAL; @@ -851,7 +864,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_start); __must_check int media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; int ret; mutex_lock(&mdev->graph_mutex); @@ -888,7 +901,7 @@ EXPORT_SYMBOL_GPL(__media_pipeline_stop); void media_pipeline_stop(struct media_pad *pad) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; mutex_lock(&mdev->graph_mutex); __media_pipeline_stop(pad); @@ -898,7 +911,7 @@ EXPORT_SYMBOL_GPL(media_pipeline_stop); __must_check int media_pipeline_alloc_start(struct media_pad *pad) { - struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_device *mdev = pad->graph_obj.mdev; struct media_pipeline *new_pipe = NULL; struct media_pipeline *pipe; int ret; @@ -906,7 +919,7 @@ __must_check int media_pipeline_alloc_start(struct media_pad *pad) mutex_lock(&mdev->graph_mutex); /* - * Is the entity already part of a pipeline? If not, we need to allocate + * Is the pad already part of a pipeline? If not, we need to allocate * a pipe. */ pipe = media_pad_pipeline(pad); @@ -932,6 +945,61 @@ out: } EXPORT_SYMBOL_GPL(media_pipeline_alloc_start); +struct media_pad * +__media_pipeline_pad_iter_next(struct media_pipeline *pipe, + struct media_pipeline_pad_iter *iter, + struct media_pad *pad) +{ + if (!pad) + iter->cursor = pipe->pads.next; + + if (iter->cursor == &pipe->pads) + return NULL; + + pad = list_entry(iter->cursor, struct media_pipeline_pad, list)->pad; + iter->cursor = iter->cursor->next; + + return pad; +} +EXPORT_SYMBOL_GPL(__media_pipeline_pad_iter_next); + +int media_pipeline_entity_iter_init(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter) +{ + return media_entity_enum_init(&iter->ent_enum, pipe->mdev); +} +EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_init); + +void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter) +{ + media_entity_enum_cleanup(&iter->ent_enum); +} +EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_cleanup); + +struct media_entity * +__media_pipeline_entity_iter_next(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter, + struct media_entity *entity) +{ + if (!entity) + iter->cursor = pipe->pads.next; + + while (iter->cursor != &pipe->pads) { + struct media_pipeline_pad *ppad; + struct media_entity *entity; + + ppad = list_entry(iter->cursor, struct media_pipeline_pad, list); + entity = ppad->pad->entity; + iter->cursor = iter->cursor->next; + + if (!media_entity_enum_test_and_set(&iter->ent_enum, entity)) + return entity; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(__media_pipeline_entity_iter_next); + /* ----------------------------------------------------------------------------- * Links management */ diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index dff0b450f387..480194543d05 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -27,6 +27,7 @@ if MEDIA_ANALOG_TV_SUPPORT source "drivers/media/pci/dt3155/Kconfig" source "drivers/media/pci/ivtv/Kconfig" +source "drivers/media/pci/saa7146/Kconfig" endif @@ -57,6 +58,7 @@ source "drivers/media/pci/pluto2/Kconfig" source "drivers/media/pci/pt1/Kconfig" source "drivers/media/pci/pt3/Kconfig" source "drivers/media/pci/smipcie/Kconfig" +source "drivers/media/pci/ttpci/Kconfig" endif diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 8f887a8a7f17..8bed619b7130 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -5,7 +5,8 @@ # Please keep it alphabetically sorted by directory # (e. g. LC_ALL=C sort Makefile) -obj-y += b2c2/ \ +obj-y += ttpci/ \ + b2c2/ \ pluto2/ \ dm1105/ \ pt1/ \ @@ -13,6 +14,7 @@ obj-y += b2c2/ \ mantis/ \ ngene/ \ ddbridge/ \ + saa7146/ \ smipcie/ \ netup_unidvb/ \ intel/ diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 390bd5ea3472..3b76a9d0383a 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1843,6 +1843,9 @@ static void cio2_pci_remove(struct pci_dev *pci_dev) v4l2_device_unregister(&cio2->v4l2_dev); media_device_cleanup(&cio2->media_dev); mutex_destroy(&cio2->lock); + + pm_runtime_forbid(&pci_dev->dev); + pm_runtime_get_noresume(&pci_dev->dev); } static int __maybe_unused cio2_runtime_suspend(struct device *dev) diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 96328b0af164..cf2871306987 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -978,7 +978,7 @@ static void saa7134_unregister_video(struct saa7134_dev *dev) } if (dev->radio_dev) { if (video_is_registered(dev->radio_dev)) - vb2_video_unregister_device(dev->radio_dev); + video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); dev->radio_dev = NULL; diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig index 228e8d3f8d2b..3bbb68a0ed7b 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig +++ b/drivers/media/pci/saa7146/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber (DEPRECATED)" + tristate "Hexium Gemini frame grabber" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help @@ -8,28 +8,22 @@ config VIDEO_HEXIUM_GEMINI grabber card by Hexium. Please note that the Gemini Dual card is *not* fully supported. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - To compile this driver as a module, choose M here: the module will be called hexium_gemini. config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber (DEPRECATED)" + tristate "Hexium HV-PCI6 and Orion frame grabber" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help This is a video4linux driver for the Hexium HV-PCI6 and Orion frame grabber cards by Hexium. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - To compile this driver as a module, choose M here: the module will be called hexium_orion. config VIDEO_MXB - tristate "Siemens-Nixdorf 'Multimedia eXtension Board' (DEPRECATED)" + tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV select VIDEO_TUNER @@ -41,8 +35,5 @@ config VIDEO_MXB This is a video4linux driver for the 'Multimedia eXtension Board' TV card by Siemens-Nixdorf. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - To compile this driver as a module, choose M here: the module will be called mxb. diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/Makefile b/drivers/media/pci/saa7146/Makefile index 37c9336f83d5..37c9336f83d5 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/Makefile +++ b/drivers/media/pci/saa7146/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 124e82bd4507..3947701cd6c7 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -13,9 +13,9 @@ #define DEBUG_VARIABLE debug +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> #include <linux/kernel.h> -#include "../common/saa7146_vv.h" static int debug; module_param(debug, int, 0); diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index ebd63998ac79..2eb4bee16b71 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -13,9 +13,9 @@ #define DEBUG_VARIABLE debug +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> #include <linux/kernel.h> -#include "../common/saa7146_vv.h" static int debug; module_param(debug, int, 0); diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 3e568f952dae..7ded8f5b05cb 100644 --- a/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -13,13 +13,13 @@ #define DEBUG_VARIABLE debug +#include <media/drv-intf/saa7146_vv.h> #include <media/tuner.h> #include <media/v4l2-common.h> #include <media/i2c/saa7115.h> #include <linux/module.h> #include <linux/kernel.h> -#include "../common/saa7146_vv.h" #include "tea6415c.h" #include "tea6420.h" diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig index 8c85ed58e938..65a6832a6b96 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI) (DEPRECATED)" + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" depends on DVB_CORE && PCI && I2C select VIDEO_SAA7146 select TTPCI_EEPROM @@ -10,7 +10,7 @@ config DVB_BUDGET_CORE MPEG2 decoder. config DVB_BUDGET - tristate "Budget cards (DEPRECATED)" + tristate "Budget cards" depends on DVB_BUDGET_CORE && I2C select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT @@ -30,16 +30,13 @@ config DVB_BUDGET or Nova-PCI cards) without onboard MPEG2 decoder, and without analog inputs or an onboard Common Interface connector. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the module will be called budget. config DVB_BUDGET_CI - tristate "Budget cards with onboard CI connector (DEPRECATED)" + tristate "Budget cards with onboard CI connector" depends on DVB_BUDGET_CORE && I2C select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT @@ -60,16 +57,13 @@ config DVB_BUDGET_CI Note: The Common Interface is not yet supported by this driver due to lack of information from the vendor. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the module will be called budget-ci. config DVB_BUDGET_AV - tristate "Budget cards with analog video inputs (DEPRECATED)" + tristate "Budget cards with analog video inputs" depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV @@ -86,9 +80,6 @@ config DVB_BUDGET_AV (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, but with one or more analog video inputs. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile index b0708f6e40cc..b0708f6e40cc 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/Makefile +++ b/drivers/media/pci/ttpci/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index 0c61a2dec221..3cb83005cf09 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -29,7 +29,7 @@ #include "tda1004x.h" #include "tua6100.h" #include "dvb-pll.h" -#include "../common/saa7146_vv.h" +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/slab.h> diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index d59d18647371..d59d18647371 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c index 5d5796f24469..5d5796f24469 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c +++ b/drivers/media/pci/ttpci/budget-core.c diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index a88711a3ac7f..a88711a3ac7f 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h index 82cc0df492b3..bd87432e6cde 100644 --- a/drivers/staging/media/deprecated/saa7146/ttpci/budget.h +++ b/drivers/media/pci/ttpci/budget.h @@ -13,7 +13,7 @@ #include <linux/module.h> #include <linux/mutex.h> -#include "../common/saa7146.h" +#include <media/drv-intf/saa7146.h> extern int budget_debug; diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 3cbe8ce637e5..e6e8fe45fc7c 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -250,19 +250,10 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) } if (V4L2_TYPE_IS_OUTPUT(f->type)) { - if (!vpu_color_check_primaries(pix_mp->colorspace)) { - venc->params.color.primaries = pix_mp->colorspace; - vpu_color_get_default(venc->params.color.primaries, - &venc->params.color.transfer, - &venc->params.color.matrix, - &venc->params.color.full_range); - } - if (!vpu_color_check_transfers(pix_mp->xfer_func)) - venc->params.color.transfer = pix_mp->xfer_func; - if (!vpu_color_check_matrix(pix_mp->ycbcr_enc)) - venc->params.color.matrix = pix_mp->ycbcr_enc; - if (!vpu_color_check_full_range(pix_mp->quantization)) - venc->params.color.full_range = pix_mp->quantization; + venc->params.color.primaries = pix_mp->colorspace; + venc->params.color.transfer = pix_mp->xfer_func; + venc->params.color.matrix = pix_mp->ycbcr_enc; + venc->params.color.full_range = pix_mp->quantization; } pix_mp->colorspace = venc->params.color.primaries; @@ -1281,7 +1272,6 @@ static void venc_init(struct file *file) f.fmt.pix_mp.width = 1280; f.fmt.pix_mp.height = 720; f.fmt.pix_mp.field = V4L2_FIELD_NONE; - f.fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; venc_s_fmt(file, &inst->fh, &f); memset(&f, 0, sizeof(f)); diff --git a/drivers/media/platform/amphion/vpu_color.c b/drivers/media/platform/amphion/vpu_color.c index 80b9a53fd1c1..4ae435cbc5cd 100644 --- a/drivers/media/platform/amphion/vpu_color.c +++ b/drivers/media/platform/amphion/vpu_color.c @@ -17,7 +17,7 @@ #include "vpu_helpers.h" static const u8 colorprimaries[] = { - 0, + V4L2_COLORSPACE_LAST, V4L2_COLORSPACE_REC709, /*Rec. ITU-R BT.709-6*/ 0, 0, @@ -31,7 +31,7 @@ static const u8 colorprimaries[] = { }; static const u8 colortransfers[] = { - 0, + V4L2_XFER_FUNC_LAST, V4L2_XFER_FUNC_709, /*Rec. ITU-R BT.709-6*/ 0, 0, @@ -53,7 +53,7 @@ static const u8 colortransfers[] = { }; static const u8 colormatrixcoefs[] = { - 0, + V4L2_YCBCR_ENC_LAST, V4L2_YCBCR_ENC_709, /*Rec. ITU-R BT.709-6*/ 0, 0, diff --git a/drivers/media/platform/chips-media/imx-vdoa.c b/drivers/media/platform/chips-media/imx-vdoa.c index c70871bae193..c3561fcecb98 100644 --- a/drivers/media/platform/chips-media/imx-vdoa.c +++ b/drivers/media/platform/chips-media/imx-vdoa.c @@ -324,11 +324,6 @@ static int vdoa_probe(struct platform_device *pdev) return 0; } -static int vdoa_remove(struct platform_device *pdev) -{ - return 0; -} - static const struct of_device_id vdoa_dt_ids[] = { { .compatible = "fsl,imx6q-vdoa" }, {} @@ -337,7 +332,6 @@ MODULE_DEVICE_TABLE(of, vdoa_dt_ids); static struct platform_driver vdoa_driver = { .probe = vdoa_probe, - .remove = vdoa_remove, .driver = { .name = VDOA_NAME, .of_match_table = vdoa_dt_ids, diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c index df16899ab1cb..ef22bf8f276c 100644 --- a/drivers/media/platform/marvell/mmp-driver.c +++ b/drivers/media/platform/marvell/mmp-driver.c @@ -254,7 +254,7 @@ static int mmpcam_probe(struct platform_device *pdev) */ ret = mccic_register(mcam); if (ret) - return ret; + goto out; /* * Add OF clock provider. diff --git a/drivers/media/platform/mediatek/mdp3/Kconfig b/drivers/media/platform/mediatek/mdp3/Kconfig index 846e759a8f6a..602329c44750 100644 --- a/drivers/media/platform/mediatek/mdp3/Kconfig +++ b/drivers/media/platform/mediatek/mdp3/Kconfig @@ -3,14 +3,13 @@ config VIDEO_MEDIATEK_MDP3 tristate "MediaTek MDP v3 driver" depends on MTK_IOMMU || COMPILE_TEST depends on VIDEO_DEV - depends on ARCH_MEDIATEK || COMPILE_TEST depends on HAS_DMA depends on REMOTEPROC + depends on MTK_MMSYS + depends on MTK_CMDQ + depends on MTK_SCP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - select MTK_MMSYS - select MTK_CMDQ - select MTK_SCP default n help It is a v4l2 driver and present in MediaTek MT8183 SoC. diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 7bc05f42a23c..091a68685590 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -1002,7 +1002,8 @@ int mdp_comp_config(struct mdp_dev *mdp) if (!pdev) { dev_warn(dev, "can't find platform device of node:%s\n", node->name); - return -ENODEV; + ret = -ENODEV; + goto err_init_comps; } comp->comp_dev = &pdev->dev; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 2d1f6ae9f080..97edcd9d1c81 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -207,8 +207,8 @@ static int mdp_probe(struct platform_device *pdev) } for (i = 0; i < MDP_PIPE_MAX; i++) { mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev); - if (!mdp->mdp_mutex[i]) { - ret = -ENODEV; + if (IS_ERR(mdp->mdp_mutex[i])) { + ret = PTR_ERR(mdp->mdp_mutex[i]); goto err_free_mutex; } } @@ -289,7 +289,8 @@ err_deinit_comp: mdp_comp_destroy(mdp); err_free_mutex: for (i = 0; i < MDP_PIPE_MAX; i++) - mtk_mutex_put(mdp->mdp_mutex[i]); + if (!IS_ERR_OR_NULL(mdp->mdp_mutex[i])) + mtk_mutex_put(mdp->mdp_mutex[i]); err_destroy_device: kfree(mdp); err_return: diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c index 4305e4eb9900..777d445999e9 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c @@ -72,9 +72,9 @@ static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) { int ret; - ret = pm_runtime_put_sync(pm->dev); - if (ret) - mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); + ret = pm_runtime_put(pm->dev); + if (ret && ret != -EAGAIN) + mtk_v4l2_err("pm_runtime_put fail %d", ret); } static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) diff --git a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c index 13c4f860fa69..60fd165c0d94 100644 --- a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c @@ -565,7 +565,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst, *bs_size); ++inst->frm_cnt; ++inst->skip_frm_cnt; - return ret; + return 0; } irq_status = h264_enc_wait_venc_done(inst); @@ -580,7 +580,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst, mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-", inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm); - return ret; + return 0; } static void h264_encode_filler(struct venc_h264_inst *inst, void *buf, diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index e2994d48f10c..71758ee8474b 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -32,10 +32,6 @@ #include "microchip-isc-regs.h" #include "microchip-isc.h" -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); - #define ISC_IS_FORMAT_RAW(mbus_code) \ (((mbus_code) & 0xf000) == 0x3000) @@ -114,8 +110,8 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) unsigned long size = isc->fmt.fmt.pix.sizeimage; if (vb2_plane_size(vb, 0) < size) { - v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); + dev_err(isc->dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); return -EINVAL; } @@ -346,15 +342,14 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) /* Enable stream on the sub device */ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", - ret); + dev_err(isc->dev, "stream on failed in subdev %d\n", ret); goto err_start_stream; } ret = pm_runtime_resume_and_get(isc->dev); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n", - ret); + dev_err(isc->dev, "RPM resume failed in subdev %d\n", + ret); goto err_pm_get; } @@ -423,8 +418,7 @@ static void isc_stop_streaming(struct vb2_queue *vq) /* Wait until the end of the current frame */ if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ)) - v4l2_err(&isc->v4l2_dev, - "Timeout waiting for end of the capture\n"); + dev_err(isc->dev, "Timeout waiting for end of the capture\n"); mutex_unlock(&isc->awb_mutex); @@ -436,7 +430,7 @@ static void isc_stop_streaming(struct vb2_queue *vq) /* Disable stream on the sub device */ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); if (ret && ret != -ENOIOCTLCMD) - v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n"); + dev_err(isc->dev, "stream off failed in subdev\n"); /* Release all active buffers */ spin_lock_irqsave(&isc->dma_queue_lock, flags); @@ -620,28 +614,28 @@ static int isc_try_validate_formats(struct isc_device *isc) break; default: /* any other different formats are not supported */ - v4l2_err(&isc->v4l2_dev, "Requested unsupported format.\n"); + dev_err(isc->dev, "Requested unsupported format.\n"); ret = -EINVAL; } - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", - rgb, yuv, grey, bayer); + dev_dbg(isc->dev, + "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", + rgb, yuv, grey, bayer); if (bayer && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - v4l2_err(&isc->v4l2_dev, "Cannot output RAW if we do not receive RAW.\n"); + dev_err(isc->dev, "Cannot output RAW if we do not receive RAW.\n"); return -EINVAL; } if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) && !ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) { - v4l2_err(&isc->v4l2_dev, "Cannot output GREY if we do not receive RAW/GREY.\n"); + dev_err(isc->dev, "Cannot output GREY if we do not receive RAW/GREY.\n"); return -EINVAL; } if ((rgb || bayer || yuv) && ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) { - v4l2_err(&isc->v4l2_dev, "Cannot convert GREY to another format.\n"); + dev_err(isc->dev, "Cannot convert GREY to another format.\n"); return -EINVAL; } @@ -936,9 +930,9 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) isc->config = isc->try_config; isc->fmt = isc->try_fmt; - v4l2_dbg(1, debug, &isc->v4l2_dev, "ISC set_fmt to %.4s @%dx%d\n", - (char *)&f->fmt.pix.pixelformat, - f->fmt.pix.width, f->fmt.pix.height); + dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n", + (char *)&f->fmt.pix.pixelformat, + f->fmt.pix.width, f->fmt.pix.height); return 0; } @@ -973,9 +967,9 @@ static int isc_validate(struct isc_device *isc) /* Check if the format is not supported */ if (!sd_fmt) { - v4l2_err(&isc->v4l2_dev, - "Current subdevice is streaming a media bus code that is not supported 0x%x\n", - format.format.code); + dev_err(isc->dev, + "Current subdevice is streaming a media bus code that is not supported 0x%x\n", + format.format.code); return -EPIPE; } @@ -993,16 +987,16 @@ static int isc_validate(struct isc_device *isc) /* Check if the frame size is the same. Otherwise we may overflow */ if (pixfmt->height != format.format.height || pixfmt->width != format.format.width) { - v4l2_err(&isc->v4l2_dev, - "ISC not configured with the proper frame size: %dx%d\n", - format.format.width, format.format.height); + dev_err(isc->dev, + "ISC not configured with the proper frame size: %dx%d\n", + format.format.width, format.format.height); return -EPIPE; } - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Identified subdev using format %.4s with %dx%d %d bpp\n", - (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height, - isc->try_config.bpp); + dev_dbg(isc->dev, + "Identified subdev using format %.4s with %dx%d %d bpp\n", + (char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height, + isc->try_config.bpp); /* Reset and restart AWB if the subdevice changed the format */ if (isc->try_config.sd_format && isc->config.sd_format && @@ -1027,7 +1021,7 @@ static int isc_validate(struct isc_device *isc) isc->config = isc->try_config; - v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); + dev_dbg(isc->dev, "New ISC configuration in place\n"); return 0; } @@ -1294,9 +1288,8 @@ static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) if (!*min) *min = 1; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: hist_id %u, hist_count %u", - ctrls->hist_id, *hist_count); + dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u", + ctrls->hist_id, *hist_count); } static void isc_wb_update(struct isc_ctrls *ctrls) @@ -1318,8 +1311,7 @@ static void isc_wb_update(struct isc_ctrls *ctrls) (u64)hist_count[ISC_HIS_CFG_MODE_GB]; avg >>= 1; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: green components average %llu\n", avg); + dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg); /* Green histogram is null, nothing to do */ if (!avg) @@ -1373,9 +1365,9 @@ static void isc_wb_update(struct isc_ctrls *ctrls) else gw_gain[c] = 1 << 9; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: component %d, s_gain %u, gw_gain %u\n", - c, s_gain[c], gw_gain[c]); + dev_dbg(isc->dev, + "isc wb: component %d, s_gain %u, gw_gain %u\n", + c, s_gain[c], gw_gain[c]); /* multiply both gains and adjust for decimals */ ctrls->gain[c] = s_gain[c] * gw_gain[c]; ctrls->gain[c] >>= 9; @@ -1383,9 +1375,8 @@ static void isc_wb_update(struct isc_ctrls *ctrls) /* make sure we are not out of range */ ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0)); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb: component %d, final gain %u\n", - c, ctrls->gain[c]); + dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n", + c, ctrls->gain[c]); } } @@ -1406,8 +1397,8 @@ static void isc_awb_work(struct work_struct *w) isc_hist_count(isc, &min, &max); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max); + dev_dbg(isc->dev, + "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max); ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; @@ -1446,8 +1437,8 @@ static void isc_awb_work(struct work_struct *w) * we are basically done. */ if (ctrls->awb == ISC_WB_ONETIME) { - v4l2_info(&isc->v4l2_dev, - "Completed one time white-balance adjustment.\n"); + dev_info(isc->dev, + "Completed one time white-balance adjustment.\n"); /* update the v4l2 controls values */ isc_update_v4l2_ctrls(isc); ctrls->awb = ISC_WB_NONE; @@ -1580,8 +1571,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) V4L2_CTRL_FLAG_INACTIVE)) { ctrls->awb = ISC_WB_ONETIME; isc_set_histogram(isc, true); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "One time white-balance started.\n"); + dev_dbg(isc->dev, "One time white-balance started.\n"); } return 0; } @@ -1730,7 +1720,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier, int pad; if (video_is_registered(&isc->video_dev)) { - v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); + dev_err(isc->dev, "only supports one sub-device.\n"); return -EBUSY; } @@ -1739,8 +1729,7 @@ static int isc_async_bound(struct v4l2_async_notifier *notifier, pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, MEDIA_PAD_FL_SOURCE); if (pad < 0) { - v4l2_err(&isc->v4l2_dev, "failed to find pad for %s\n", - subdev->name); + dev_err(isc->dev, "failed to find pad for %s\n", subdev->name); return pad; } @@ -1813,7 +1802,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); + dev_err(isc->dev, "Failed to register subdev nodes\n"); return ret; } @@ -1838,8 +1827,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = vb2_queue_init(q); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "vb2_queue_init() failed: %d\n", ret); + dev_err(isc->dev, "vb2_queue_init() failed: %d\n", ret); goto isc_async_complete_err; } @@ -1850,13 +1838,13 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = isc_set_default_fmt(isc); if (ret) { - v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); + dev_err(isc->dev, "Could not set default format\n"); goto isc_async_complete_err; } ret = isc_ctrl_init(isc); if (ret) { - v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); + dev_err(isc->dev, "Init isc ctrols failed: %d\n", ret); goto isc_async_complete_err; } @@ -1876,8 +1864,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "video_register_device failed: %d\n", ret); + dev_err(isc->dev, "video_register_device failed: %d\n", ret); goto isc_async_complete_err; } diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index f6d48c36f386..189d60cd5ed1 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -1571,7 +1571,7 @@ static int dw100_probe(struct platform_device *pdev) dev_name(&pdev->dev), dw_dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); - return ret; + goto err_pm; } ret = v4l2_device_register(&pdev->dev, &dw_dev->v4l2_dev); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 6cd015a35f7c..f085f14d676a 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -2472,19 +2472,12 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->mode = mode; /* Get clocks */ - jpeg->clk_ipg = devm_clk_get(dev, "ipg"); - if (IS_ERR(jpeg->clk_ipg)) { - dev_err(dev, "failed to get clock: ipg\n"); - ret = PTR_ERR(jpeg->clk_ipg); - goto err_clk; - } - - jpeg->clk_per = devm_clk_get(dev, "per"); - if (IS_ERR(jpeg->clk_per)) { - dev_err(dev, "failed to get clock: per\n"); - ret = PTR_ERR(jpeg->clk_per); + ret = devm_clk_bulk_get_all(&pdev->dev, &jpeg->clks); + if (ret < 0) { + dev_err(dev, "failed to get clock\n"); goto err_clk; } + jpeg->num_clks = ret; ret = mxc_jpeg_attach_pm_domains(jpeg); if (ret < 0) { @@ -2581,32 +2574,20 @@ static int mxc_jpeg_runtime_resume(struct device *dev) struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(jpeg->clk_ipg); - if (ret < 0) { - dev_err(dev, "failed to enable clock: ipg\n"); - goto err_ipg; - } - - ret = clk_prepare_enable(jpeg->clk_per); + ret = clk_bulk_prepare_enable(jpeg->num_clks, jpeg->clks); if (ret < 0) { - dev_err(dev, "failed to enable clock: per\n"); - goto err_per; + dev_err(dev, "failed to enable clock\n"); + return ret; } return 0; - -err_per: - clk_disable_unprepare(jpeg->clk_ipg); -err_ipg: - return ret; } static int mxc_jpeg_runtime_suspend(struct device *dev) { struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); - clk_disable_unprepare(jpeg->clk_ipg); - clk_disable_unprepare(jpeg->clk_per); + clk_bulk_disable_unprepare(jpeg->num_clks, jpeg->clks); return 0; } diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index 8fa8c0aec5a2..87157db78082 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -120,8 +120,8 @@ struct mxc_jpeg_dev { spinlock_t hw_lock; /* hardware access lock */ unsigned int mode; struct mutex lock; /* v4l2 ioctls serialization */ - struct clk *clk_ipg; - struct clk *clk_per; + struct clk_bulk_data *clks; + int num_clks; struct platform_device *pdev; struct device *dev; void __iomem *base_reg; diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 905072871ed2..be2768a47995 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -327,10 +327,6 @@ struct mipi_csis_device { u32 hs_settle; u32 clk_settle; - struct mutex lock; /* Protect csis_fmt and format_mbus */ - const struct csis_pix_format *csis_fmt; - struct v4l2_mbus_framefmt format_mbus[CSIS_PADS_NUM]; - spinlock_t slock; /* Protect events */ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; struct dentry *debugfs_root; @@ -559,10 +555,10 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on) mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val); } -/* Called with the csis.lock mutex held */ -static void __mipi_csis_set_format(struct mipi_csis_device *csis) +static void __mipi_csis_set_format(struct mipi_csis_device *csis, + const struct v4l2_mbus_framefmt *format, + const struct csis_pix_format *csis_fmt) { - struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK]; u32 val; /* Color format */ @@ -583,25 +579,26 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis) * * TODO: Verify which other formats require DUAL (or QUAD) modes. */ - if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) + if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; - val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type); + val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type); mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val); /* Pixel resolution */ - val = mf->width | (mf->height << 16); + val = format->width | (format->height << 16); mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val); } -static int mipi_csis_calculate_params(struct mipi_csis_device *csis) +static int mipi_csis_calculate_params(struct mipi_csis_device *csis, + const struct csis_pix_format *csis_fmt) { s64 link_freq; u32 lane_rate; /* Calculate the line rate from the pixel rate. */ link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler, - csis->csis_fmt->width, + csis_fmt->width, csis->bus.num_data_lanes * 2); if (link_freq < 0) { dev_err(csis->dev, "Unable to obtain link frequency: %d\n", @@ -643,7 +640,9 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis) return 0; } -static void mipi_csis_set_params(struct mipi_csis_device *csis) +static void mipi_csis_set_params(struct mipi_csis_device *csis, + const struct v4l2_mbus_framefmt *format, + const struct csis_pix_format *csis_fmt) { int lanes = csis->bus.num_data_lanes; u32 val; @@ -655,7 +654,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis) val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); - __mipi_csis_set_format(csis); + __mipi_csis_set_format(csis, format, csis_fmt); mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) | @@ -728,10 +727,12 @@ static int mipi_csis_clk_get(struct mipi_csis_device *csis) return ret; } -static void mipi_csis_start_stream(struct mipi_csis_device *csis) +static void mipi_csis_start_stream(struct mipi_csis_device *csis, + const struct v4l2_mbus_framefmt *format, + const struct csis_pix_format *csis_fmt) { mipi_csis_sw_reset(csis); - mipi_csis_set_params(csis); + mipi_csis_set_params(csis, format, csis_fmt); mipi_csis_system_enable(csis, true); mipi_csis_enable_interrupts(csis, true); } @@ -935,120 +936,63 @@ static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev) static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) { struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); + const struct v4l2_mbus_framefmt *format; + const struct csis_pix_format *csis_fmt; + struct v4l2_subdev_state *state; int ret; if (!enable) { - mutex_lock(&csis->lock); - v4l2_subdev_call(csis->src_sd, video, s_stream, 0); mipi_csis_stop_stream(csis); if (csis->debug.enable) mipi_csis_log_counters(csis, true); - mutex_unlock(&csis->lock); - pm_runtime_put(csis->dev); return 0; } - ret = mipi_csis_calculate_params(csis); + state = v4l2_subdev_lock_and_get_active_state(sd); + + format = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SINK); + csis_fmt = find_csis_format(format->code); + + ret = mipi_csis_calculate_params(csis, csis_fmt); if (ret < 0) - return ret; + goto err_unlock; mipi_csis_clear_counters(csis); ret = pm_runtime_resume_and_get(csis->dev); if (ret < 0) - return ret; + goto err_unlock; - mutex_lock(&csis->lock); + mipi_csis_start_stream(csis, format, csis_fmt); - mipi_csis_start_stream(csis); ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1); if (ret < 0) - goto error; + goto err_stop; mipi_csis_log_counters(csis, true); - mutex_unlock(&csis->lock); + v4l2_subdev_unlock_state(state); return 0; -error: +err_stop: mipi_csis_stop_stream(csis); - mutex_unlock(&csis->lock); pm_runtime_put(csis->dev); +err_unlock: + v4l2_subdev_unlock_state(state); return ret; } -static struct v4l2_mbus_framefmt * -mipi_csis_get_format(struct mipi_csis_device *csis, - struct v4l2_subdev_state *sd_state, - enum v4l2_subdev_format_whence which, - unsigned int pad) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad); - - return &csis->format_mbus[pad]; -} - -static int mipi_csis_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) -{ - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - struct v4l2_mbus_framefmt *fmt_sink; - struct v4l2_mbus_framefmt *fmt_source; - enum v4l2_subdev_format_whence which; - - which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SINK); - - fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; - fmt_sink->height = MIPI_CSIS_DEF_PIX_HEIGHT; - fmt_sink->field = V4L2_FIELD_NONE; - - fmt_sink->colorspace = V4L2_COLORSPACE_SMPTE170M; - fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace); - fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace); - fmt_sink->quantization = - V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, - fmt_sink->ycbcr_enc); - - fmt_source = mipi_csis_get_format(csis, sd_state, which, - CSIS_PAD_SOURCE); - *fmt_source = *fmt_sink; - - return 0; -} - -static int mipi_csis_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat) -{ - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - struct v4l2_mbus_framefmt *fmt; - - fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, - sdformat->pad); - - mutex_lock(&csis->lock); - sdformat->format = *fmt; - mutex_unlock(&csis->lock); - - return 0; -} - static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - /* * The CSIS can't transcode in any way, the source format is identical * to the sink format. @@ -1059,8 +1003,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = mipi_csis_get_format(csis, sd_state, code->which, - code->pad); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad); code->code = fmt->code; return 0; } @@ -1080,7 +1023,6 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *fmt; unsigned int align; @@ -1090,7 +1032,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, * modified. */ if (sdformat->pad == CSIS_PAD_SOURCE) - return mipi_csis_get_fmt(sd, sd_state, sdformat); + return v4l2_subdev_get_fmt(sd, sd_state, sdformat); if (sdformat->pad != CSIS_PAD_SINK) return -EINVAL; @@ -1128,14 +1070,12 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, &sdformat->format.height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0); - fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, - sdformat->pad); - - mutex_lock(&csis->lock); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; fmt->height = sdformat->format.height; + fmt->field = V4L2_FIELD_NONE; fmt->colorspace = sdformat->format.colorspace; fmt->quantization = sdformat->format.quantization; fmt->xfer_func = sdformat->format.xfer_func; @@ -1144,48 +1084,68 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, - CSIS_PAD_SOURCE); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE); *fmt = sdformat->format; /* The format on the source pad might change due to unpacking. */ fmt->code = csis_fmt->output; - /* Store the CSIS format descriptor for active formats. */ - if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csis->csis_fmt = csis_fmt; - - mutex_unlock(&csis->lock); - return 0; } static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_frame_desc *fd) { - struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0]; + const struct csis_pix_format *csis_fmt; + const struct v4l2_mbus_framefmt *fmt; + struct v4l2_subdev_state *state; if (pad != CSIS_PAD_SOURCE) return -EINVAL; + state = v4l2_subdev_lock_and_get_active_state(sd); + fmt = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SOURCE); + csis_fmt = find_csis_format(fmt->code); + v4l2_subdev_unlock_state(state); + + if (!csis_fmt) + return -EPIPE; + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; fd->num_entries = 1; memset(entry, 0, sizeof(*entry)); - mutex_lock(&csis->lock); - entry->flags = 0; - entry->pixelcode = csis->csis_fmt->code; + entry->pixelcode = csis_fmt->code; entry->bus.csi2.vc = 0; - entry->bus.csi2.dt = csis->csis_fmt->data_type; - - mutex_unlock(&csis->lock); + entry->bus.csi2.dt = csis_fmt->data_type; return 0; } +static int mipi_csis_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format fmt = { + .pad = CSIS_PAD_SINK, + }; + + fmt.format.code = mipi_csis_formats[0].code; + fmt.format.width = MIPI_CSIS_DEF_PIX_WIDTH; + fmt.format.height = MIPI_CSIS_DEF_PIX_HEIGHT; + + fmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt.format.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt.format.colorspace); + fmt.format.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt.format.colorspace); + fmt.format.quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt.format.colorspace, + fmt.format.ycbcr_enc); + + return mipi_csis_set_fmt(sd, sd_state, &fmt); +} + static int mipi_csis_log_status(struct v4l2_subdev *sd) { struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); @@ -1208,7 +1168,7 @@ static const struct v4l2_subdev_video_ops mipi_csis_video_ops = { static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { .init_cfg = mipi_csis_init_cfg, .enum_mbus_code = mipi_csis_enum_mbus_code, - .get_fmt = mipi_csis_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mipi_csis_set_fmt, .get_frame_desc = mipi_csis_get_frame_desc, }; @@ -1348,40 +1308,34 @@ static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - int ret = 0; - - mutex_lock(&csis->lock); + int ret; ret = mipi_csis_phy_disable(csis); if (ret) - goto unlock; + return -EAGAIN; mipi_csis_clk_disable(csis); -unlock: - mutex_unlock(&csis->lock); - - return ret ? -EAGAIN : 0; + return 0; } static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - int ret = 0; - - mutex_lock(&csis->lock); + int ret; ret = mipi_csis_phy_enable(csis); if (ret) - goto unlock; - - mipi_csis_clk_enable(csis); + return -EAGAIN; -unlock: - mutex_unlock(&csis->lock); + ret = mipi_csis_clk_enable(csis); + if (ret) { + mipi_csis_phy_disable(csis); + return ret; + } - return ret ? -EAGAIN : 0; + return 0; } static const struct dev_pm_ops mipi_csis_pm_ops = { @@ -1396,6 +1350,7 @@ static const struct dev_pm_ops mipi_csis_pm_ops = { static int mipi_csis_subdev_init(struct mipi_csis_device *csis) { struct v4l2_subdev *sd = &csis->sd; + int ret; v4l2_subdev_init(sd, &mipi_csis_subdev_ops); sd->owner = THIS_MODULE; @@ -1417,15 +1372,21 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis) return -ENOENT; } - csis->csis_fmt = &mipi_csis_formats[0]; - mipi_csis_init_cfg(sd, NULL); - csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; - return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, - csis->pads); + ret = media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, csis->pads); + if (ret) + return ret; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) { + media_entity_cleanup(&sd->entity); + return ret; + } + + return 0; } static int mipi_csis_parse_dt(struct mipi_csis_device *csis) @@ -1450,7 +1411,6 @@ static int mipi_csis_probe(struct platform_device *pdev) if (!csis) return -ENOMEM; - mutex_init(&csis->lock); spin_lock_init(&csis->slock); csis->dev = dev; @@ -1496,20 +1456,20 @@ static int mipi_csis_probe(struct platform_device *pdev) dev_name(dev), csis); if (ret) { dev_err(dev, "Interrupt request failed\n"); - goto disable_clock; + goto err_disable_clock; } /* Initialize and register the subdev. */ ret = mipi_csis_subdev_init(csis); if (ret < 0) - goto disable_clock; + goto err_disable_clock; platform_set_drvdata(pdev, &csis->sd); ret = mipi_csis_async_register(csis); if (ret < 0) { dev_err(dev, "async register failed: %d\n", ret); - goto cleanup; + goto err_cleanup; } /* Initialize debugfs. */ @@ -1520,7 +1480,7 @@ static int mipi_csis_probe(struct platform_device *pdev) if (!pm_runtime_enabled(dev)) { ret = mipi_csis_runtime_resume(dev); if (ret < 0) - goto unregister_all; + goto err_unregister_all; } dev_info(dev, "lanes: %d, freq: %u\n", @@ -1528,17 +1488,17 @@ static int mipi_csis_probe(struct platform_device *pdev) return 0; -unregister_all: +err_unregister_all: mipi_csis_debugfs_exit(csis); -cleanup: +err_cleanup: + v4l2_subdev_cleanup(&csis->sd); media_entity_cleanup(&csis->sd.entity); v4l2_async_nf_unregister(&csis->notifier); v4l2_async_nf_cleanup(&csis->notifier); v4l2_async_unregister_subdev(&csis->sd); -disable_clock: +err_disable_clock: mipi_csis_clk_disable(csis); fwnode_handle_put(csis->sd.fwnode); - mutex_destroy(&csis->lock); return ret; } @@ -1556,9 +1516,9 @@ static int mipi_csis_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); mipi_csis_runtime_suspend(&pdev->dev); mipi_csis_clk_disable(csis); + v4l2_subdev_cleanup(&csis->sd); media_entity_cleanup(&csis->sd.entity); fwnode_handle_put(csis->sd.fwnode); - mutex_destroy(&csis->lock); pm_runtime_set_suspended(&pdev->dev); return 0; diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 689ae5e6ac62..fde3c36e5e1d 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -10,6 +10,7 @@ * Pawel Osciak, <pawel@osciak.com> * Marek Szyprowski, <m.szyprowski@samsung.com> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -18,15 +19,18 @@ #include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/platform_device.h> -#include <media/v4l2-mem2mem.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> +#include <media/media-device.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> #include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mem2mem.h> #include <media/videobuf2-dma-contig.h> #include "imx-pxp.h" @@ -52,6 +56,11 @@ MODULE_PARM_DESC(debug, "activates debug info"); #define MEM2MEM_HFLIP (1 << 0) #define MEM2MEM_VFLIP (1 << 1) +#define PXP_VERSION_MAJOR(version) \ + FIELD_GET(BM_PXP_VERSION_MAJOR, version) +#define PXP_VERSION_MINOR(version) \ + FIELD_GET(BM_PXP_VERSION_MINOR, version) + #define dprintk(dev, fmt, arg...) \ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) @@ -168,14 +177,21 @@ enum { V4L2_M2M_DST = 1, }; -static struct pxp_fmt *find_format(struct v4l2_format *f) +static const struct regmap_config pxp_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = HW_PXP_VERSION, +}; + +static struct pxp_fmt *find_format(unsigned int pixelformat) { struct pxp_fmt *fmt; unsigned int k; for (k = 0; k < NUM_FORMATS; k++) { fmt = &formats[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) + if (fmt->fourcc == pixelformat) break; } @@ -185,12 +201,23 @@ static struct pxp_fmt *find_format(struct v4l2_format *f) return &formats[k]; } +struct pxp_ctx; + +struct pxp_pdata { + u32 (*data_path_ctrl0)(struct pxp_ctx *ctx); +}; + struct pxp_dev { struct v4l2_device v4l2_dev; struct video_device vfd; +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device mdev; +#endif struct clk *clk; - void __iomem *mmio; + struct regmap *regmap; + + const struct pxp_pdata *pdata; atomic_t num_inst; struct mutex dev_mutex; @@ -234,6 +261,20 @@ static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx, return &ctx->q_data[V4L2_M2M_DST]; } +static inline u32 pxp_read(struct pxp_dev *dev, u32 reg) +{ + u32 value; + + regmap_read(dev->regmap, reg, &value); + + return value; +} + +static inline void pxp_write(struct pxp_dev *dev, u32 reg, u32 value) +{ + regmap_write(dev->regmap, reg, value); +} + static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt) { switch (v4l2_pix_fmt) { @@ -486,11 +527,11 @@ static void pxp_setup_csc(struct pxp_ctx *ctx) csc1_coef = csc1_coef_smpte240m_lim; } - writel(csc1_coef[0], dev->mmio + HW_PXP_CSC1_COEF0); - writel(csc1_coef[1], dev->mmio + HW_PXP_CSC1_COEF1); - writel(csc1_coef[2], dev->mmio + HW_PXP_CSC1_COEF2); + pxp_write(dev, HW_PXP_CSC1_COEF0, csc1_coef[0]); + pxp_write(dev, HW_PXP_CSC1_COEF1, csc1_coef[1]); + pxp_write(dev, HW_PXP_CSC1_COEF2, csc1_coef[2]); } else { - writel(BM_PXP_CSC1_COEF0_BYPASS, dev->mmio + HW_PXP_CSC1_COEF0); + pxp_write(dev, HW_PXP_CSC1_COEF0, BM_PXP_CSC1_COEF0_BYPASS); } if (!pxp_v4l2_pix_fmt_is_yuv(ctx->q_data[V4L2_M2M_SRC].fmt->fourcc) && @@ -706,18 +747,95 @@ static void pxp_setup_csc(struct pxp_ctx *ctx) BP_PXP_CSC2_CTRL_CSC_MODE; } - writel(csc2_ctrl, dev->mmio + HW_PXP_CSC2_CTRL); - writel(csc2_coef[0], dev->mmio + HW_PXP_CSC2_COEF0); - writel(csc2_coef[1], dev->mmio + HW_PXP_CSC2_COEF1); - writel(csc2_coef[2], dev->mmio + HW_PXP_CSC2_COEF2); - writel(csc2_coef[3], dev->mmio + HW_PXP_CSC2_COEF3); - writel(csc2_coef[4], dev->mmio + HW_PXP_CSC2_COEF4); - writel(csc2_coef[5], dev->mmio + HW_PXP_CSC2_COEF5); + pxp_write(dev, HW_PXP_CSC2_CTRL, csc2_ctrl); + pxp_write(dev, HW_PXP_CSC2_COEF0, csc2_coef[0]); + pxp_write(dev, HW_PXP_CSC2_COEF1, csc2_coef[1]); + pxp_write(dev, HW_PXP_CSC2_COEF2, csc2_coef[2]); + pxp_write(dev, HW_PXP_CSC2_COEF3, csc2_coef[3]); + pxp_write(dev, HW_PXP_CSC2_COEF4, csc2_coef[4]); + pxp_write(dev, HW_PXP_CSC2_COEF5, csc2_coef[5]); } else { - writel(BM_PXP_CSC2_CTRL_BYPASS, dev->mmio + HW_PXP_CSC2_CTRL); + pxp_write(dev, HW_PXP_CSC2_CTRL, BM_PXP_CSC2_CTRL_BYPASS); } } +static u32 pxp_imx6ull_data_path_ctrl0(struct pxp_ctx *ctx) +{ + u32 ctrl0; + + ctrl0 = 0; + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3); + /* Bypass Dithering x3CH */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3); + /* Select Rotation */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0); + /* Bypass LUT */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3); + /* Select CSC 2 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3); + /* Bypass Rotation 2 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3); + + return ctrl0; +} + +static u32 pxp_imx7d_data_path_ctrl0(struct pxp_ctx *ctx) +{ + u32 ctrl0; + + ctrl0 = 0; + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(3); + /* Select Rotation 0 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(3); + /* Select MUX11 for Rotation 0 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(1); + /* Bypass LUT */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(3); + /* Select CSC 2 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(3); + /* Select Composite Alpha Blending/Color Key 0 for CSC 2 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(1); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(3); + /* Bypass Rotation 1 */ + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(3); + ctrl0 |= BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(3); + + return ctrl0; +} + +static void pxp_set_data_path(struct pxp_ctx *ctx) +{ + struct pxp_dev *dev = ctx->dev; + u32 ctrl0; + u32 ctrl1; + + ctrl0 = dev->pdata->data_path_ctrl0(ctx); + + ctrl1 = 0; + ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(3); + ctrl1 |= BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(3); + + pxp_write(dev, HW_PXP_DATA_PATH_CTRL0, ctrl0); + pxp_write(dev, HW_PXP_DATA_PATH_CTRL1, ctrl1); +} + static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, struct vb2_v4l2_buffer *out_vb) { @@ -871,67 +989,48 @@ static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, BF_PXP_PS_SCALE_XSCALE(xscale); ps_offset = BF_PXP_PS_OFFSET_YOFFSET(0) | BF_PXP_PS_OFFSET_XOFFSET(0); - writel(ctrl, dev->mmio + HW_PXP_CTRL); + pxp_write(dev, HW_PXP_CTRL, ctrl); /* skip STAT */ - writel(out_ctrl, dev->mmio + HW_PXP_OUT_CTRL); - writel(out_buf, dev->mmio + HW_PXP_OUT_BUF); - writel(out_buf2, dev->mmio + HW_PXP_OUT_BUF2); - writel(out_pitch, dev->mmio + HW_PXP_OUT_PITCH); - writel(out_lrc, dev->mmio + HW_PXP_OUT_LRC); - writel(out_ps_ulc, dev->mmio + HW_PXP_OUT_PS_ULC); - writel(out_ps_lrc, dev->mmio + HW_PXP_OUT_PS_LRC); - writel(as_ulc, dev->mmio + HW_PXP_OUT_AS_ULC); - writel(as_lrc, dev->mmio + HW_PXP_OUT_AS_LRC); - writel(ps_ctrl, dev->mmio + HW_PXP_PS_CTRL); - writel(ps_buf, dev->mmio + HW_PXP_PS_BUF); - writel(ps_ubuf, dev->mmio + HW_PXP_PS_UBUF); - writel(ps_vbuf, dev->mmio + HW_PXP_PS_VBUF); - writel(ps_pitch, dev->mmio + HW_PXP_PS_PITCH); - writel(0x00ffffff, dev->mmio + HW_PXP_PS_BACKGROUND_0); - writel(ps_scale, dev->mmio + HW_PXP_PS_SCALE); - writel(ps_offset, dev->mmio + HW_PXP_PS_OFFSET); + pxp_write(dev, HW_PXP_OUT_CTRL, out_ctrl); + pxp_write(dev, HW_PXP_OUT_BUF, out_buf); + pxp_write(dev, HW_PXP_OUT_BUF2, out_buf2); + pxp_write(dev, HW_PXP_OUT_PITCH, out_pitch); + pxp_write(dev, HW_PXP_OUT_LRC, out_lrc); + pxp_write(dev, HW_PXP_OUT_PS_ULC, out_ps_ulc); + pxp_write(dev, HW_PXP_OUT_PS_LRC, out_ps_lrc); + pxp_write(dev, HW_PXP_OUT_AS_ULC, as_ulc); + pxp_write(dev, HW_PXP_OUT_AS_LRC, as_lrc); + pxp_write(dev, HW_PXP_PS_CTRL, ps_ctrl); + pxp_write(dev, HW_PXP_PS_BUF, ps_buf); + pxp_write(dev, HW_PXP_PS_UBUF, ps_ubuf); + pxp_write(dev, HW_PXP_PS_VBUF, ps_vbuf); + pxp_write(dev, HW_PXP_PS_PITCH, ps_pitch); + pxp_write(dev, HW_PXP_PS_BACKGROUND_0, 0x00ffffff); + pxp_write(dev, HW_PXP_PS_SCALE, ps_scale); + pxp_write(dev, HW_PXP_PS_OFFSET, ps_offset); /* disable processed surface color keying */ - writel(0x00ffffff, dev->mmio + HW_PXP_PS_CLRKEYLOW_0); - writel(0x00000000, dev->mmio + HW_PXP_PS_CLRKEYHIGH_0); + pxp_write(dev, HW_PXP_PS_CLRKEYLOW_0, 0x00ffffff); + pxp_write(dev, HW_PXP_PS_CLRKEYHIGH_0, 0x00000000); /* disable alpha surface color keying */ - writel(0x00ffffff, dev->mmio + HW_PXP_AS_CLRKEYLOW_0); - writel(0x00000000, dev->mmio + HW_PXP_AS_CLRKEYHIGH_0); + pxp_write(dev, HW_PXP_AS_CLRKEYLOW_0, 0x00ffffff); + pxp_write(dev, HW_PXP_AS_CLRKEYHIGH_0, 0x00000000); /* setup CSC */ pxp_setup_csc(ctx); /* bypass LUT */ - writel(BM_PXP_LUT_CTRL_BYPASS, dev->mmio + HW_PXP_LUT_CTRL); - - writel(BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1)| - BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1)| - BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0)| - BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0), - dev->mmio + HW_PXP_DATA_PATH_CTRL0); - writel(BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1) | - BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1), - dev->mmio + HW_PXP_DATA_PATH_CTRL1); - - writel(0xffff, dev->mmio + HW_PXP_IRQ_MASK); + pxp_write(dev, HW_PXP_LUT_CTRL, BM_PXP_LUT_CTRL_BYPASS); + + pxp_set_data_path(ctx); + + pxp_write(dev, HW_PXP_IRQ_MASK, 0xffff); /* ungate, enable PS/AS/OUT and PXP operation */ - writel(BM_PXP_CTRL_IRQ_ENABLE, dev->mmio + HW_PXP_CTRL_SET); - writel(BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 | - BM_PXP_CTRL_ENABLE_LUT | BM_PXP_CTRL_ENABLE_ROTATE0 | - BM_PXP_CTRL_ENABLE_PS_AS_OUT, dev->mmio + HW_PXP_CTRL_SET); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_IRQ_ENABLE); + pxp_write(dev, HW_PXP_CTRL_SET, + BM_PXP_CTRL_ENABLE | BM_PXP_CTRL_ENABLE_CSC2 | + BM_PXP_CTRL_ENABLE_ROTATE0 | BM_PXP_CTRL_ENABLE_PS_AS_OUT); return 0; } @@ -1004,23 +1103,23 @@ static irqreturn_t pxp_irq_handler(int irq, void *dev_id) struct pxp_dev *dev = dev_id; u32 stat; - stat = readl(dev->mmio + HW_PXP_STAT); + stat = pxp_read(dev, HW_PXP_STAT); if (stat & BM_PXP_STAT_IRQ0) { /* we expect x = 0, y = height, irq0 = 1 */ if (stat & ~(BM_PXP_STAT_BLOCKX | BM_PXP_STAT_BLOCKY | BM_PXP_STAT_IRQ0)) dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat); - writel(BM_PXP_STAT_IRQ0, dev->mmio + HW_PXP_STAT_CLR); + pxp_write(dev, HW_PXP_STAT_CLR, BM_PXP_STAT_IRQ0); pxp_job_finish(dev); } else { - u32 irq = readl(dev->mmio + HW_PXP_IRQ); + u32 irq = pxp_read(dev, HW_PXP_IRQ); dprintk(dev, "%s: stat = 0x%08x\n", __func__, stat); dprintk(dev, "%s: irq = 0x%08x\n", __func__, irq); - writel(irq, dev->mmio + HW_PXP_IRQ_CLR); + pxp_write(dev, HW_PXP_IRQ_CLR, irq); } return IRQ_HANDLED; @@ -1034,8 +1133,6 @@ static int pxp_querycap(struct file *file, void *priv, { strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", MEM2MEM_NAME); return 0; } @@ -1181,10 +1278,10 @@ static int pxp_try_fmt_vid_cap(struct file *file, void *priv, struct pxp_fmt *fmt; struct pxp_ctx *ctx = file2ctx(file); - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); if (!fmt) { f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); } if (!(fmt->types & MEM2MEM_CAPTURE)) { v4l2_err(&ctx->dev->v4l2_dev, @@ -1209,10 +1306,10 @@ static int pxp_try_fmt_vid_out(struct file *file, void *priv, struct pxp_fmt *fmt; struct pxp_ctx *ctx = file2ctx(file); - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); if (!fmt) { f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); } if (!(fmt->types & MEM2MEM_OUTPUT)) { v4l2_err(&ctx->dev->v4l2_dev, @@ -1245,7 +1342,7 @@ static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f) return -EBUSY; } - q_data->fmt = find_format(f); + q_data->fmt = find_format(f->fmt.pix.pixelformat); q_data->width = f->fmt.pix.width; q_data->height = f->fmt.pix.height; q_data->bytesperline = f->fmt.pix.bytesperline; @@ -1304,6 +1401,26 @@ static int pxp_s_fmt_vid_out(struct file *file, void *priv, return 0; } +static int pxp_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (!find_format(fsize->pixel_format)) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_W; + fsize->stepwise.max_width = MAX_W; + fsize->stepwise.step_width = 1 << ALIGN_W; + fsize->stepwise.min_height = MIN_H; + fsize->stepwise.max_height = MAX_H; + fsize->stepwise.step_height = 1 << ALIGN_H; + + return 0; +} + static u8 pxp_degrees_to_rot_mode(u32 degrees) { switch (degrees) { @@ -1372,6 +1489,8 @@ static const struct v4l2_ioctl_ops pxp_ioctl_ops = { .vidioc_try_fmt_vid_out = pxp_try_fmt_vid_out, .vidioc_s_fmt_vid_out = pxp_s_fmt_vid_out, + .vidioc_enum_framesizes = pxp_enum_framesizes, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, @@ -1644,18 +1763,18 @@ static int pxp_soft_reset(struct pxp_dev *dev) int ret; u32 val; - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR); - writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE); - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST); - ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val, - val & BM_PXP_CTRL_CLKGATE, 0, 100); + ret = regmap_read_poll_timeout(dev->regmap, HW_PXP_CTRL, val, + val & BM_PXP_CTRL_CLKGATE, 0, 100); if (ret < 0) return ret; - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR); - writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_SFTRST); + pxp_write(dev, HW_PXP_CTRL_CLR, BM_PXP_CTRL_CLKGATE); return 0; } @@ -1664,13 +1783,17 @@ static int pxp_probe(struct platform_device *pdev) { struct pxp_dev *dev; struct video_device *vfd; + u32 hw_version; int irq; int ret; + void __iomem *mmio; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; + dev->pdata = of_device_get_match_data(&pdev->dev); + dev->clk = devm_clk_get(&pdev->dev, "axi"); if (IS_ERR(dev->clk)) { ret = PTR_ERR(dev->clk); @@ -1678,9 +1801,11 @@ static int pxp_probe(struct platform_device *pdev) return ret; } - dev->mmio = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(dev->mmio)) - return PTR_ERR(dev->mmio); + mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, + &pxp_regmap_config); irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -1688,8 +1813,8 @@ static int pxp_probe(struct platform_device *pdev) spin_lock_init(&dev->irqlock); - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler, - IRQF_ONESHOT, dev_name(&pdev->dev), dev); + ret = devm_request_irq(&pdev->dev, irq, pxp_irq_handler, 0, + dev_name(&pdev->dev), dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); return ret; @@ -1705,6 +1830,10 @@ static int pxp_probe(struct platform_device *pdev) goto err_clk; } + hw_version = pxp_read(dev, HW_PXP_VERSION); + dev_dbg(&pdev->dev, "PXP Version %u.%u\n", + PXP_VERSION_MAJOR(hw_version), PXP_VERSION_MINOR(hw_version)); + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) goto err_clk; @@ -1737,8 +1866,34 @@ static int pxp_probe(struct platform_device *pdev) goto err_m2m; } +#ifdef CONFIG_MEDIA_CONTROLLER + dev->mdev.dev = &pdev->dev; + strscpy(dev->mdev.model, MEM2MEM_NAME, sizeof(dev->mdev.model)); + media_device_init(&dev->mdev); + dev->v4l2_dev.mdev = &dev->mdev; + + ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize media device\n"); + goto err_vfd; + } + + ret = media_device_register(&dev->mdev); + if (ret) { + dev_err(&pdev->dev, "Failed to register media device\n"); + goto err_m2m_mc; + } +#endif + return 0; +#ifdef CONFIG_MEDIA_CONTROLLER +err_m2m_mc: + v4l2_m2m_unregister_media_controller(dev->m2m_dev); +err_vfd: + video_unregister_device(vfd); +#endif err_m2m: v4l2_m2m_release(dev->m2m_dev); err_v4l2: @@ -1753,12 +1908,17 @@ static int pxp_remove(struct platform_device *pdev) { struct pxp_dev *dev = platform_get_drvdata(pdev); - writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_SET); - writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_SET); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_CLKGATE); + pxp_write(dev, HW_PXP_CTRL_SET, BM_PXP_CTRL_SFTRST); clk_disable_unprepare(dev->clk); v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); + +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_unregister(&dev->mdev); + v4l2_m2m_unregister_media_controller(dev->m2m_dev); +#endif video_unregister_device(&dev->vfd); v4l2_m2m_release(dev->m2m_dev); v4l2_device_unregister(&dev->v4l2_dev); @@ -1766,8 +1926,17 @@ static int pxp_remove(struct platform_device *pdev) return 0; } +static const struct pxp_pdata pxp_imx6ull_pdata = { + .data_path_ctrl0 = pxp_imx6ull_data_path_ctrl0, +}; + +static const struct pxp_pdata pxp_imx7d_pdata = { + .data_path_ctrl0 = pxp_imx7d_data_path_ctrl0, +}; + static const struct of_device_id pxp_dt_ids[] = { - { .compatible = "fsl,imx6ull-pxp", .data = NULL }, + { .compatible = "fsl,imx6ull-pxp", .data = &pxp_imx6ull_pdata }, + { .compatible = "fsl,imx7d-pxp", .data = &pxp_imx7d_pdata }, { }, }; MODULE_DEVICE_TABLE(of, pxp_dt_ids); diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 886374d3a6ff..c22bf5c827e7 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -211,7 +211,6 @@ struct imx7_csi { int irq; struct clk *mclk; - struct mutex lock; /* Protects is_streaming, format_mbus, cc */ spinlock_t irqlock; /* Protects last_eof */ /* Media and V4L2 device */ @@ -227,9 +226,6 @@ struct imx7_csi { struct v4l2_subdev sd; struct media_pad pad[IMX7_CSI_PADS_NUM]; - struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM]; - const struct imx7_csi_pixfmt *cc[IMX7_CSI_PADS_NUM]; - /* Video device */ struct video_device *vdev; /* Video device */ struct media_pad vdev_pad; /* Video device pad */ @@ -510,7 +506,8 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi) imx7_csi_hw_disable_irq(csi); } -static void imx7_csi_configure(struct imx7_csi *csi) +static void imx7_csi_configure(struct imx7_csi *csi, + struct v4l2_subdev_state *sd_state) { struct v4l2_pix_format *out_pix = &csi->vdev_fmt; int width = out_pix->width; @@ -541,12 +538,17 @@ static void imx7_csi_configure(struct imx7_csi *csi) out_pix->pixelformat == V4L2_PIX_FMT_YUYV) width *= 2; } else { + const struct v4l2_mbus_framefmt *sink_fmt; + + sink_fmt = v4l2_subdev_get_pad_format(&csi->sd, sd_state, + IMX7_CSI_PAD_SINK); + cr1 = BIT_SOF_POL | BIT_REDGE | BIT_HSYNC_POL | BIT_FCC | BIT_MCLKDIV(1) | BIT_MCLKEN; cr18 |= BIT_DATA_FROM_MIPI; - switch (csi->format_mbus[IMX7_CSI_PAD_SINK].code) { + switch (sink_fmt->code) { case MEDIA_BUS_FMT_Y8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: @@ -627,7 +629,8 @@ static void imx7_csi_configure(struct imx7_csi *csi) imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA); } -static int imx7_csi_init(struct imx7_csi *csi) +static int imx7_csi_init(struct imx7_csi *csi, + struct v4l2_subdev_state *sd_state) { int ret; @@ -635,11 +638,13 @@ static int imx7_csi_init(struct imx7_csi *csi) if (ret < 0) return ret; - imx7_csi_configure(csi); + imx7_csi_configure(csi, sd_state); ret = imx7_csi_dma_setup(csi); - if (ret < 0) + if (ret < 0) { + clk_disable_unprepare(csi->mclk); return ret; + } return 0; } @@ -1411,14 +1416,15 @@ static void imx7_csi_video_buf_queue(struct vb2_buffer *vb) static int imx7_csi_video_validate_fmt(struct imx7_csi *csi) { - struct v4l2_subdev_format fmt_src; + struct v4l2_subdev_format fmt_src = { + .pad = IMX7_CSI_PAD_SRC, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; const struct imx7_csi_pixfmt *cc; int ret; /* Retrieve the media bus format on the source subdev. */ - fmt_src.pad = IMX7_CSI_PAD_SRC; - fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(&csi->sd, pad, get_fmt, NULL, &fmt_src); + ret = v4l2_subdev_call_state_active(&csi->sd, pad, get_fmt, &fmt_src); if (ret) return ret; @@ -1599,17 +1605,15 @@ static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi) static int imx7_csi_video_init_format(struct imx7_csi *csi) { - struct v4l2_subdev_format fmt_src = { - .pad = IMX7_CSI_PAD_SRC, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - fmt_src.format.code = IMX7_CSI_DEF_MBUS_CODE; - fmt_src.format.width = IMX7_CSI_DEF_PIX_WIDTH; - fmt_src.format.height = IMX7_CSI_DEF_PIX_HEIGHT; + struct v4l2_mbus_framefmt format = { }; + + format.code = IMX7_CSI_DEF_MBUS_CODE; + format.width = IMX7_CSI_DEF_PIX_WIDTH; + format.height = IMX7_CSI_DEF_PIX_HEIGHT; - imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &fmt_src.format, NULL); - csi->vdev_compose.width = fmt_src.format.width; - csi->vdev_compose.height = fmt_src.format.height; + imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &format, NULL); + csi->vdev_compose.width = format.width; + csi->vdev_compose.height = format.height; csi->vdev_cc = imx7_csi_find_pixel_format(csi->vdev_fmt.pixelformat); @@ -1728,20 +1732,13 @@ static int imx7_csi_video_init(struct imx7_csi *csi) static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); + struct v4l2_subdev_state *sd_state; int ret = 0; - mutex_lock(&csi->lock); - - if (!csi->src_sd) { - ret = -EPIPE; - goto out_unlock; - } - - if (csi->is_streaming == !!enable) - goto out_unlock; + sd_state = v4l2_subdev_lock_and_get_active_state(sd); if (enable) { - ret = imx7_csi_init(csi); + ret = imx7_csi_init(csi, sd_state); if (ret < 0) goto out_unlock; @@ -1763,29 +1760,14 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) csi->is_streaming = !!enable; out_unlock: - mutex_unlock(&csi->lock); + v4l2_subdev_unlock_state(sd_state); return ret; } -static struct v4l2_mbus_framefmt * -imx7_csi_get_format(struct imx7_csi *csi, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); - - return &csi->format_mbus[pad]; -} - static int imx7_csi_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { - const enum v4l2_subdev_format_whence which = - sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - struct imx7_csi *csi = v4l2_get_subdevdata(sd); const struct imx7_csi_pixfmt *cc; int i; @@ -1793,7 +1775,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd, for (i = 0; i < IMX7_CSI_PADS_NUM; i++) { struct v4l2_mbus_framefmt *mf = - imx7_csi_get_format(csi, sd_state, i, which); + v4l2_subdev_get_pad_format(sd, sd_state, i); mf->code = IMX7_CSI_DEF_MBUS_CODE; mf->width = IMX7_CSI_DEF_PIX_WIDTH; @@ -1805,8 +1787,6 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd, mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace); mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv, mf->colorspace, mf->ycbcr_enc); - - csi->cc[i] = cc; } return 0; @@ -1816,59 +1796,30 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct imx7_csi *csi = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *in_fmt; int ret = 0; - mutex_lock(&csi->lock); - - in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK, - code->which); + in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK); switch (code->pad) { case IMX7_CSI_PAD_SINK: ret = imx7_csi_enum_mbus_formats(&code->code, code->index); break; + case IMX7_CSI_PAD_SRC: if (code->index != 0) { ret = -EINVAL; - goto out_unlock; + break; } code->code = in_fmt->code; break; - default: - ret = -EINVAL; - } - -out_unlock: - mutex_unlock(&csi->lock); - - return ret; -} -static int imx7_csi_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat) -{ - struct imx7_csi *csi = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *fmt; - int ret = 0; - - mutex_lock(&csi->lock); - - fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad, - sdformat->which); - if (!fmt) { + default: ret = -EINVAL; - goto out_unlock; + break; } - sdformat->format = *fmt; - -out_unlock: - mutex_unlock(&csi->lock); - return ret; } @@ -1918,19 +1869,16 @@ static void imx7_csi_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt) tryfmt->ycbcr_enc); } -static int imx7_csi_try_fmt(struct imx7_csi *csi, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat, - const struct imx7_csi_pixfmt **cc) +static void imx7_csi_try_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat, + const struct imx7_csi_pixfmt **cc) { const struct imx7_csi_pixfmt *in_cc; struct v4l2_mbus_framefmt *in_fmt; u32 code; - in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK, - sdformat->which); - if (!in_fmt) - return -EINVAL; + in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK); switch (sdformat->pad) { case IMX7_CSI_PAD_SRC: @@ -1947,6 +1895,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, sdformat->format.quantization = in_fmt->quantization; sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc; break; + case IMX7_CSI_PAD_SINK: *cc = imx7_csi_find_mbus_format(sdformat->format.code); if (!*cc) { @@ -1958,13 +1907,9 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, if (sdformat->format.field != V4L2_FIELD_INTERLACED) sdformat->format.field = V4L2_FIELD_NONE; break; - default: - return -EINVAL; } imx7_csi_try_colorimetry(&sdformat->format); - - return 0; } static int imx7_csi_set_fmt(struct v4l2_subdev *sd, @@ -1977,28 +1922,13 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, const struct imx7_csi_pixfmt *cc; struct v4l2_mbus_framefmt *fmt; struct v4l2_subdev_format format; - int ret = 0; - - if (sdformat->pad >= IMX7_CSI_PADS_NUM) - return -EINVAL; - - mutex_lock(&csi->lock); - if (csi->is_streaming) { - ret = -EBUSY; - goto out_unlock; - } + if (csi->is_streaming) + return -EBUSY; - ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc); - if (ret < 0) - goto out_unlock; + imx7_csi_try_fmt(sd, sd_state, sdformat, &cc); - fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad, - sdformat->which); - if (!fmt) { - ret = -EINVAL; - goto out_unlock; - } + fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad); *fmt = sdformat->format; @@ -2007,25 +1937,14 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, format.pad = IMX7_CSI_PAD_SRC; format.which = sdformat->which; format.format = sdformat->format; - if (imx7_csi_try_fmt(csi, sd_state, &format, &outcc)) { - ret = -EINVAL; - goto out_unlock; - } - outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC, - sdformat->which); - *outfmt = format.format; + imx7_csi_try_fmt(sd, sd_state, &format, &outcc); - if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csi->cc[IMX7_CSI_PAD_SRC] = outcc; + outfmt = v4l2_subdev_get_pad_format(sd, sd_state, + IMX7_CSI_PAD_SRC); + *outfmt = format.format; } - if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csi->cc[sdformat->pad] = cc; - -out_unlock: - mutex_unlock(&csi->lock); - - return ret; + return 0; } static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd, @@ -2038,9 +1957,6 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd, unsigned int i; int ret; - if (!csi->src_sd) - return -EPIPE; - /* * Validate the source link, and record whether the source uses the * parallel input or the CSI-2 receiver. @@ -2128,7 +2044,7 @@ static const struct v4l2_subdev_video_ops imx7_csi_video_ops = { static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = { .init_cfg = imx7_csi_init_cfg, .enum_mbus_code = imx7_csi_enum_mbus_code, - .get_fmt = imx7_csi_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx7_csi_set_fmt, .link_validate = imx7_csi_pad_link_validate, }; @@ -2201,7 +2117,7 @@ static int imx7_csi_async_register(struct imx7_csi *csi) ret = PTR_ERR(asd); /* OK if asd already exists */ if (ret != -EEXIST) - return ret; + goto error; } } @@ -2209,15 +2125,20 @@ static int imx7_csi_async_register(struct imx7_csi *csi) ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); if (ret) - return ret; + goto error; return 0; + +error: + v4l2_async_nf_cleanup(&csi->notifier); + return ret; } static void imx7_csi_media_cleanup(struct imx7_csi *csi) { v4l2_device_unregister(&csi->v4l2_dev); media_device_unregister(&csi->mdev); + v4l2_subdev_cleanup(&csi->sd); media_device_cleanup(&csi->mdev); } @@ -2285,6 +2206,10 @@ static int imx7_csi_media_init(struct imx7_csi *csi) if (ret) goto error; + ret = v4l2_subdev_init_finalize(&csi->sd); + if (ret) + goto error; + ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd); if (ret) goto error; @@ -2310,27 +2235,22 @@ static int imx7_csi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, csi); spin_lock_init(&csi->irqlock); - mutex_init(&csi->lock); /* Acquire resources and install interrupt handler. */ csi->mclk = devm_clk_get(&pdev->dev, "mclk"); if (IS_ERR(csi->mclk)) { ret = PTR_ERR(csi->mclk); dev_err(dev, "Failed to get mclk: %d", ret); - goto destroy_mutex; + return ret; } csi->irq = platform_get_irq(pdev, 0); - if (csi->irq < 0) { - ret = csi->irq; - goto destroy_mutex; - } + if (csi->irq < 0) + return csi->irq; csi->regbase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(csi->regbase)) { - ret = PTR_ERR(csi->regbase); - goto destroy_mutex; - } + if (IS_ERR(csi->regbase)) + return PTR_ERR(csi->regbase); csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev); @@ -2338,34 +2258,23 @@ static int imx7_csi_probe(struct platform_device *pdev) (void *)csi); if (ret < 0) { dev_err(dev, "Request CSI IRQ failed.\n"); - goto destroy_mutex; + return ret; } /* Initialize all the media device infrastructure. */ ret = imx7_csi_media_init(csi); if (ret) - goto destroy_mutex; - - /* Set the default mbus formats. */ - ret = imx7_csi_init_cfg(&csi->sd, NULL); - if (ret) - goto media_cleanup; + return ret; ret = imx7_csi_async_register(csi); if (ret) - goto subdev_notifier_cleanup; + goto err_media_cleanup; return 0; -subdev_notifier_cleanup: - v4l2_async_nf_unregister(&csi->notifier); - v4l2_async_nf_cleanup(&csi->notifier); -media_cleanup: +err_media_cleanup: imx7_csi_media_cleanup(csi); -destroy_mutex: - mutex_destroy(&csi->lock); - return ret; } @@ -2379,8 +2288,6 @@ static int imx7_csi_remove(struct platform_device *pdev) v4l2_async_nf_cleanup(&csi->notifier); v4l2_async_unregister_subdev(&csi->sd); - mutex_destroy(&csi->lock); - return 0; } diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 451a4c9b3d30..04baa80494c6 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -429,7 +429,8 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, array_size = ARRAY_SIZE(lane_regs_sm8250[0]); break; default: - unreachable(); + WARN(1, "unknown cspi version\n"); + return; } for (l = 0; l < 5; l++) { diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index 33e08efa3039..384fb54e219a 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -406,7 +406,7 @@ static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2) if (!(rzg2l_csi2_read(csi2, CSI2nRTST) & CSI2nRTST_VSRSTS)) break; usleep_range(100, 200); - }; + } if (!timeout) dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n"); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index 91b57c7c2e56..e6eedd65b71d 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -404,7 +404,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru) break; usleep_range(10, 20); - }; + } /* Notify that AXI bus can not stop here */ if (!retries) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index d4540684ea9a..d1d1fdce03e3 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -1131,10 +1131,12 @@ static void rkisp1_try_fmt(const struct rkisp1_capture *cap, const struct rkisp1_capture_config *config = cap->config; const struct rkisp1_capture_fmt_cfg *fmt; const struct v4l2_format_info *info; - const unsigned int max_widths[] = { RKISP1_RSZ_MP_SRC_MAX_WIDTH, - RKISP1_RSZ_SP_SRC_MAX_WIDTH }; - const unsigned int max_heights[] = { RKISP1_RSZ_MP_SRC_MAX_HEIGHT, - RKISP1_RSZ_SP_SRC_MAX_HEIGHT}; + static const unsigned int max_widths[] = { + RKISP1_RSZ_MP_SRC_MAX_WIDTH, RKISP1_RSZ_SP_SRC_MAX_WIDTH + }; + static const unsigned int max_heights[] = { + RKISP1_RSZ_MP_SRC_MAX_HEIGHT, RKISP1_RSZ_SP_SRC_MAX_HEIGHT + }; fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat); if (!fmt) { @@ -1336,8 +1338,9 @@ void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1) static int rkisp1_register_capture(struct rkisp1_capture *cap) { - const char * const dev_names[] = {RKISP1_MP_DEV_NAME, - RKISP1_SP_DEV_NAME}; + static const char * const dev_names[] = { + RKISP1_MP_DEV_NAME, RKISP1_SP_DEV_NAME + }; struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev; struct video_device *vdev = &cap->vnode.vdev; struct rkisp1_vdev_node *node; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.h b/drivers/media/platform/samsung/exynos4-is/fimc-is.h index 06586e455b1d..c126b779aafc 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.h @@ -14,7 +14,6 @@ #include <linux/clk.h> #include <linux/device.h> #include <linux/kernel.h> -#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/sizes.h> #include <linux/spinlock.h> @@ -231,7 +230,6 @@ struct chain_config { /** * struct fimc_is - fimc-is data structure * @pdev: pointer to FIMC-IS platform device - * @pctrl: pointer to pinctrl structure for this device * @v4l2_dev: pointer to the top level v4l2_device * @fw: data structure describing the FIMC-IS firmware binary * @memory: memory region assigned for the FIMC-IS (firmware) @@ -262,7 +260,6 @@ struct chain_config { */ struct fimc_is { struct platform_device *pdev; - struct pinctrl *pctrl; struct v4l2_device *v4l2_dev; struct fimc_is_firmware fw; diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h index 62ad5d7e035a..079105d88bab 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.h +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h @@ -11,7 +11,6 @@ #include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/of.h> -#include <linux/pinctrl/consumer.h> #include <media/media-device.h> #include <media/media-entity.h> #include <media/v4l2-device.h> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index f3e4cdac1ef3..9d2cce124a34 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -1021,8 +1021,8 @@ static __poll_t s5p_mfc_poll(struct file *file, * means either in driver already or waiting for driver to claim it * and start processing. */ - if ((!src_q->streaming || list_empty(&src_q->queued_list)) - && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { + if ((!vb2_is_streaming(src_q) || list_empty(&src_q->queued_list)) && + (!vb2_is_streaming(dst_q) || list_empty(&dst_q->queued_list))) { rc = EPOLLERR; goto end; } diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index 18e6c65f4737..86c5235a0c7a 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -264,6 +264,7 @@ static int sun4i_csi_remove(struct platform_device *pdev) { struct sun4i_csi *csi = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); v4l2_async_nf_unregister(&csi->notifier); v4l2_async_nf_cleanup(&csi->notifier); vb2_video_unregister_device(&csi->vdev); diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index a3e826a755fc..95b5633b7914 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -245,7 +245,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) * We need a scratch buffer in case where we'll not have any * more buffer queued so that we don't error out. One of those * cases is when you end up at the last frame to capture, you - * don't havea any buffer queued any more, and yet it doesn't + * don't have any buffer queued any more, and yet it doesn't * really matter since you'll never reach the next buffer. * * Since we support the multi-planar API, we need to have a @@ -311,7 +311,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG); /* Clear the pending interrupts */ - writel(CSI_INT_FRM_DONE, csi->regs + 0x34); + writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_STA_REG); /* Enable frame done interrupt */ writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG); diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c index 56b61c0583cf..1236215ec70e 100644 --- a/drivers/media/platform/ti/cal/cal.c +++ b/drivers/media/platform/ti/cal/cal.c @@ -1050,8 +1050,10 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->cport = inst; ret = cal_ctx_v4l2_init(ctx); - if (ret) + if (ret) { + kfree(ctx); return NULL; + } return ctx; } diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c index da27da4c165a..832489822706 100644 --- a/drivers/media/platform/ti/davinci/vpif.c +++ b/drivers/media/platform/ti/davinci/vpif.c @@ -480,7 +480,7 @@ static int vpif_probe(struct platform_device *pdev) ret = irq; goto err_put_rpm; } - res_irq = (struct resource)DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node)); + res_irq = DEFINE_RES_IRQ_NAMED(irq, of_node_full_name(pdev->dev.of_node)); res_irq.flags |= irq_get_trigger_type(irq); pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL); diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index 1d40bb59ff81..e7327e38482d 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -2307,7 +2307,16 @@ static int isp_probe(struct platform_device *pdev) /* Regulators */ isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy1"); + if (IS_ERR(isp->isp_csiphy1.vdd)) { + ret = PTR_ERR(isp->isp_csiphy1.vdd); + goto error; + } + isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy2"); + if (IS_ERR(isp->isp_csiphy2.vdd)) { + ret = PTR_ERR(isp->isp_csiphy2.vdd); + goto error; + } /* Clocks * diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 3e5348c63773..ddc7d08d4f96 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -221,22 +221,16 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad) static int isp_video_get_graph_data(struct isp_video *video, struct isp_pipeline *pipe) { - struct media_graph graph; - struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_pipeline_entity_iter iter; + struct media_entity *entity; struct isp_video *far_end = NULL; int ret; - mutex_lock(&mdev->graph_mutex); - ret = media_graph_walk_init(&graph, mdev); - if (ret) { - mutex_unlock(&mdev->graph_mutex); + ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter); + if (ret) return ret; - } - media_graph_walk_start(&graph, entity); - - while ((entity = media_graph_walk_next(&graph))) { + media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) { struct isp_video *__video; media_entity_enum_set(&pipe->ent_enum, entity); @@ -255,9 +249,7 @@ static int isp_video_get_graph_data(struct isp_video *video, far_end = __video; } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&graph); + media_pipeline_entity_iter_cleanup(&iter); if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { pipe->input = far_end; diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 8cb4a68c9119..b0aeedae7b65 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -1050,8 +1050,6 @@ static int hantro_probe(struct platform_device *pdev) vpu->mdev.dev = vpu->dev; strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); - strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME, - sizeof(vpu->mdev.bus_info)); media_device_init(&vpu->mdev); vpu->mdev.ops = &hantro_m2m_media_ops; vpu->v4l2_dev.mdev = &vpu->mdev; diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 2c7a805289e7..c0d427956210 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -142,8 +142,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver)); strscpy(cap->card, vdev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s", - vpu->dev->driver->name); return 0; } @@ -161,8 +159,11 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, } /* For non-coded formats check if postprocessing scaling is possible */ - if (fmt->codec_mode == HANTRO_MODE_NONE && hantro_needs_postproc(ctx, fmt)) { - return hanto_postproc_enum_framesizes(ctx, fsize); + if (fmt->codec_mode == HANTRO_MODE_NONE) { + if (hantro_needs_postproc(ctx, fmt)) + return hanto_postproc_enum_framesizes(ctx, fsize); + else + return -ENOTTY; } else if (fsize->index != 0) { vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", fsize->index); diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 0a7fd8642a65..fee02c8c85fd 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -173,31 +173,19 @@ done: static int xvip_pipeline_validate(struct xvip_pipeline *pipe, struct xvip_dma *start) { - struct media_graph graph; - struct media_entity *entity = &start->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_pipeline_pad_iter iter; unsigned int num_inputs = 0; unsigned int num_outputs = 0; - int ret; - - mutex_lock(&mdev->graph_mutex); - - /* Walk the graph to locate the video nodes. */ - ret = media_graph_walk_init(&graph, mdev); - if (ret) { - mutex_unlock(&mdev->graph_mutex); - return ret; - } - - media_graph_walk_start(&graph, entity); + struct media_pad *pad; - while ((entity = media_graph_walk_next(&graph))) { + /* Locate the video nodes in the pipeline. */ + media_pipeline_for_each_pad(&pipe->pipe, &iter, pad) { struct xvip_dma *dma; - if (entity->function != MEDIA_ENT_F_IO_V4L) + if (pad->entity->function != MEDIA_ENT_F_IO_V4L) continue; - dma = to_xvip_dma(media_entity_to_video_device(entity)); + dma = to_xvip_dma(media_entity_to_video_device(pad->entity)); if (dma->pad.flags & MEDIA_PAD_FL_SINK) { pipe->output = dma; @@ -207,10 +195,6 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe, } } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&graph); - /* We need exactly one output and zero or one input. */ if (num_outputs != 1 || num_inputs > 1) return -EPIPE; diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 8a316de70e6c..cbd49dff6d74 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -1442,7 +1442,7 @@ static long fm_st_receive(void *arg, struct sk_buff *skb) { struct fmdev *fmdev; - fmdev = (struct fmdev *)arg; + fmdev = arg; if (skb == NULL) { fmerr("Invalid SKB received from ST\n"); diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index f560fc38895f..ac4172feb6f9 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -314,7 +314,7 @@ config IR_PWM_TX tristate "PWM IR transmitter" depends on LIRC depends on PWM - depends on OF || COMPILE_TEST + depends on OF help Say Y if you want to use a PWM based IR transmitter. This is more power efficient than the bit banging gpio driver. @@ -361,7 +361,7 @@ config IR_SERIAL_TRANSMITTER config IR_SPI tristate "SPI connected IR LED" depends on SPI && LIRC - depends on OF || COMPILE_TEST + depends on OF help Say Y if you want to use an IR LED connected through SPI bus. diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index e09270916fbc..11ee21a7db8f 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1106,6 +1106,8 @@ static void ene_remove(struct pnp_dev *pnp_dev) struct ene_device *dev = pnp_get_drvdata(pnp_dev); unsigned long flags; + rc_unregister_device(dev->rdev); + del_timer_sync(&dev->tx_sim_timer); spin_lock_irqsave(&dev->hw_lock, flags); ene_rx_disable(dev); ene_rx_restore_hw_buffer(dev); @@ -1113,7 +1115,6 @@ static void ene_remove(struct pnp_dev *pnp_dev) free_irq(dev->irq, dev); release_region(dev->hw_io, ENE_IO_SIZE); - rc_unregister_device(dev->rdev); kfree(dev); } diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 8f1fff7af6c9..8dbe780dae4e 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -126,6 +126,23 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) "gpio-ir-recv-irq", gpio_dev); } +static int gpio_ir_recv_remove(struct platform_device *pdev) +{ + struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); + struct device *pmdev = gpio_dev->pmdev; + + if (pmdev) { + pm_runtime_get_sync(pmdev); + cpu_latency_qos_remove_request(&gpio_dev->qos); + + pm_runtime_disable(pmdev); + pm_runtime_put_noidle(pmdev); + pm_runtime_set_suspended(pmdev); + } + + return 0; +} + #ifdef CONFIG_PM static int gpio_ir_recv_suspend(struct device *dev) { @@ -185,6 +202,7 @@ MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); static struct platform_driver gpio_ir_recv_driver = { .probe = gpio_ir_recv_probe, + .remove = gpio_ir_recv_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(gpio_ir_recv_of_match), diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index 85080c3d2053..adbbe639a261 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -261,11 +261,6 @@ static int ir_rx51_probe(struct platform_device *dev) return devm_rc_register_device(&dev->dev, ir_rx51.rcdev); } -static int ir_rx51_remove(struct platform_device *dev) -{ - return 0; -} - static const struct of_device_id ir_rx51_match[] = { { .compatible = "nokia,n900-ir", @@ -276,7 +271,6 @@ MODULE_DEVICE_TABLE(of, ir_rx51_match); static struct platform_driver ir_rx51_platform_driver = { .probe = ir_rx51_probe, - .remove = ir_rx51_remove, .suspend = ir_rx51_suspend, .resume = ir_rx51_resume, .driver = { diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c index 105a9c24f1e3..7732054c4621 100644 --- a/drivers/media/rc/pwm-ir-tx.c +++ b/drivers/media/rc/pwm-ir-tx.c @@ -120,7 +120,7 @@ static struct platform_driver pwm_ir_driver = { .probe = pwm_ir_probe, .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(pwm_ir_of_match), + .of_match_table = pwm_ir_of_match, }, }; module_platform_driver(pwm_ir_driver); diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c index a5875380ef40..ce0b7a6e92dc 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_psi.c +++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c @@ -1940,7 +1940,7 @@ u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args) struct vidtv_psi_table_eit_event *vidtv_psi_eit_event_init(struct vidtv_psi_table_eit_event *head, u16 event_id) { - const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */ + static const u8 DURATION[] = {0x23, 0x59, 0x59}; /* BCD encoded */ struct vidtv_psi_table_eit_event *e; struct timespec64 ts; struct tm time; diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c index b08664dfbe5f..7cac6a6456eb 100644 --- a/drivers/media/test-drivers/visl/visl-video.c +++ b/drivers/media/test-drivers/visl/visl-video.c @@ -687,7 +687,7 @@ static void visl_buf_request_complete(struct vb2_buffer *vb) v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); } -const struct vb2_ops visl_qops = { +static const struct vb2_ops visl_qops = { .queue_setup = visl_queue_setup, .buf_out_validate = visl_buf_out_validate, .buf_prepare = visl_buf_prepare, diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 476b32c04c20..3fa3dcda917a 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -875,9 +875,9 @@ err: dev_dbg(&client->dev, "failed=%d\n", ret); } -static int si2157_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int si2157_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct si2157_config *cfg = client->dev.platform_data; struct dvb_frontend *fe = cfg->fe; struct si2157_dev *dev; @@ -990,7 +990,7 @@ static struct i2c_driver si2157_driver = { .name = "si2157", .suppress_bind_attrs = true, }, - .probe = si2157_probe, + .probe_new = si2157_probe, .remove = si2157_remove, .id_table = si2157_id_table, }; diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index d33514acc2b5..4014f7d07330 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1165,7 +1165,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* If any of these are non-zero, assume invalid data */ if (buf[1] || buf[2] || buf[3]) { dev_dbg(&intf->dev, "invalid data\n"); - return ret; + return 0; } /* Check for repeat of previous code */ @@ -1174,7 +1174,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) dev_dbg(&intf->dev, "key repeated\n"); rc_repeat(d->rc_dev); state->rc_repeat = buf[6]; - return ret; + return 0; } /* Only process key if canary killed */ diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index b2edc4deaca3..13256565b034 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -404,16 +404,13 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count) go->next_seq = 0; go->active_buf = NULL; go->modet_event_status = 0; - q->streaming = 1; if (go7007_start_encoder(go) < 0) ret = -EIO; else ret = 0; mutex_unlock(&go->hw_lock); - if (ret) { - q->streaming = 0; + if (ret) return ret; - } call_all(&go->v4l2_dev, video, s_stream, 1); v4l2_ctrl_grab(go->mpeg_video_gop_size, true); v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); @@ -430,7 +427,6 @@ static void go7007_stop_streaming(struct vb2_queue *q) struct go7007 *go = vb2_get_drv_priv(q); unsigned long flags; - q->streaming = 0; go7007_stream_stop(go); mutex_lock(&go->hw_lock); go7007_reset_encoder(go); diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index fe9c7b3a950e..6f443c542c6d 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -179,6 +179,7 @@ static void smsusb_stop_streaming(struct smsusb_device_t *dev) for (i = 0; i < MAX_URBS; i++) { usb_kill_urb(&dev->surbs[i].urb); + cancel_work_sync(&dev->surbs[i].wq); if (dev->surbs[i].cb) { smscore_putbuffer(dev->coredev, dev->surbs[i].cb); diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c index 72bd64f65198..c00197d095e7 100644 --- a/drivers/media/v4l2-core/v4l2-h264.c +++ b/drivers/media/v4l2-core/v4l2-h264.c @@ -305,6 +305,8 @@ static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *bui int n = 0, i; *out_str = kmalloc(tmp_str_size, GFP_KERNEL); + if (!(*out_str)) + return NULL; n += snprintf(*out_str + n, tmp_str_size - n, "|"); @@ -343,6 +345,8 @@ static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *bui int n = 0, i; *out_str = kmalloc(tmp_str_size, GFP_KERNEL); + if (!(*out_str)) + return NULL; n += snprintf(*out_str + n, tmp_str_size - n, "|"); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 2a0139c72d29..87f163a89c80 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/version.h> +#include <linux/v4l2-subdev.h> #include <linux/videodev2.h> #include <media/media-device.h> /* for media_set_bus_info() */ @@ -3154,6 +3155,21 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, ret = 1; break; } + + case VIDIOC_SUBDEV_G_ROUTING: + case VIDIOC_SUBDEV_S_ROUTING: { + struct v4l2_subdev_routing *routing = parg; + + if (routing->num_routes > 256) + return -E2BIG; + + *user_ptr = u64_to_user_ptr(routing->routes); + *kernel_ptr = (void **)&routing->routes; + *array_size = sizeof(struct v4l2_subdev_route) + * routing->num_routes; + ret = 1; + break; + } } return ret; @@ -3400,8 +3416,15 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, /* * Some ioctls can return an error, but still have valid * results that must be returned. + * + * FIXME: subdev IOCTLS are partially handled here and partially in + * v4l2-subdev.c and the 'always_copy' flag can only be set for IOCTLS + * defined here as part of the 'v4l2_ioctls' array. As + * VIDIOC_SUBDEV_G_ROUTING needs to return results to applications even + * in case of failure, but it is not defined here as part of the + * 'v4l2_ioctls' array, insert an ad-hoc check to address that. */ - if (err < 0 && !always_copy) + if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING) goto out; if (has_array_args) { diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c index c2513b775f6a..94435a7b6816 100644 --- a/drivers/media/v4l2-core/v4l2-jpeg.c +++ b/drivers/media/v4l2-core/v4l2-jpeg.c @@ -460,7 +460,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream, /* Check for "Adobe\0" in Ap1..6 */ if (stream->curr + 6 > stream->end || strncmp(stream->curr, "Adobe\0", 6)) - return -EINVAL; + return jpeg_skip(stream, lp - 2); /* get to Ap12 */ ret = jpeg_skip(stream, 11); @@ -474,7 +474,7 @@ static int jpeg_parse_app14_data(struct jpeg_stream *stream, *tf = ret; /* skip the rest of the segment, this ensures at least it is complete */ - skip = lp - 2 - 11; + skip = lp - 2 - 11 - 1; return jpeg_skip(stream, skip); } diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index be7fde1ed3ea..0cc30397fbad 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -922,9 +922,9 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file, * means either in driver already or waiting for driver to claim it * and start processing. */ - if ((!src_q->streaming || src_q->error || + if ((!vb2_is_streaming(src_q) || src_q->error || list_empty(&src_q->queued_list)) && - (!dst_q->streaming || dst_q->error || + (!vb2_is_streaming(dst_q) || dst_q->error || (list_empty(&dst_q->queued_list) && !dst_q->last_buffer_dequeued))) return EPOLLERR; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 6630fb30bc7d..b10045c02f43 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -8,21 +8,41 @@ * Sakari Ailus <sakari.ailus@iki.fi> */ +#include <linux/export.h> #include <linux/ioctl.h> #include <linux/leds.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/overflow.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/videodev2.h> -#include <linux/export.h> #include <linux/version.h> +#include <linux/videodev2.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-fh.h> #include <media/v4l2-event.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> + +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) +/* + * The Streams API is an experimental feature. To use the Streams API, set + * 'v4l2_subdev_enable_streams_api' to 1 below. + */ + +static bool v4l2_subdev_enable_streams_api; +#endif + +/* + * Maximum stream ID is 63 for now, as we use u64 bitmask to represent a set + * of streams. + * + * Note that V4L2_FRAME_DESC_ENTRY_MAX is related: V4L2_FRAME_DESC_ENTRY_MAX + * restricts the total number of streams in a pad, although the stream ID is + * not restricted. + */ +#define V4L2_SUBDEV_MAX_STREAM_ID 63 #include "v4l2-subdev-priv.h" @@ -151,8 +171,22 @@ static inline int check_pad(struct v4l2_subdev *sd, u32 pad) return 0; } -static int check_state_pads(u32 which, struct v4l2_subdev_state *state) +static int check_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, + u32 which, u32 pad, u32 stream) { + if (sd->flags & V4L2_SUBDEV_FL_STREAMS) { +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + if (!v4l2_subdev_state_get_stream_format(state, pad, stream)) + return -EINVAL; + return 0; +#else + return -EINVAL; +#endif + } + + if (stream != 0) + return -EINVAL; + if (which == V4L2_SUBDEV_FORMAT_TRY && (!state || !state->pads)) return -EINVAL; @@ -166,8 +200,11 @@ static inline int check_format(struct v4l2_subdev *sd, if (!format) return -EINVAL; + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) + format->stream = 0; + return check_which(format->which) ? : check_pad(sd, format->pad) ? : - check_state_pads(format->which, state); + check_state(sd, state, format->which, format->pad, format->stream); } static int call_get_fmt(struct v4l2_subdev *sd, @@ -193,8 +230,11 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd, if (!code) return -EINVAL; + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) + code->stream = 0; + return check_which(code->which) ? : check_pad(sd, code->pad) ? : - check_state_pads(code->which, state) ? : + check_state(sd, state, code->which, code->pad, code->stream) ? : sd->ops->pad->enum_mbus_code(sd, state, code); } @@ -205,8 +245,11 @@ static int call_enum_frame_size(struct v4l2_subdev *sd, if (!fse) return -EINVAL; + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) + fse->stream = 0; + return check_which(fse->which) ? : check_pad(sd, fse->pad) ? : - check_state_pads(fse->which, state) ? : + check_state(sd, state, fse->which, fse->pad, fse->stream) ? : sd->ops->pad->enum_frame_size(sd, state, fse); } @@ -240,8 +283,11 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd, if (!fie) return -EINVAL; + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) + fie->stream = 0; + return check_which(fie->which) ? : check_pad(sd, fie->pad) ? : - check_state_pads(fie->which, state) ? : + check_state(sd, state, fie->which, fie->pad, fie->stream) ? : sd->ops->pad->enum_frame_interval(sd, state, fie); } @@ -252,8 +298,11 @@ static inline int check_selection(struct v4l2_subdev *sd, if (!sel) return -EINVAL; + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) + sel->stream = 0; + return check_which(sel->which) ? : check_pad(sd, sel->pad) ? : - check_state_pads(sel->which, state); + check_state(sd, state, sel->which, sel->pad, sel->stream); } static int call_get_selection(struct v4l2_subdev *sd, @@ -444,6 +493,10 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh, case VIDIOC_SUBDEV_S_SELECTION: which = ((struct v4l2_subdev_selection *)arg)->which; break; + case VIDIOC_SUBDEV_G_ROUTING: + case VIDIOC_SUBDEV_S_ROUTING: + which = ((struct v4l2_subdev_routing *)arg)->which; + break; } return which == V4L2_SUBDEV_FORMAT_TRY ? @@ -458,6 +511,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_fh *vfh = file->private_data; bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); + bool streams_subdev = sd->flags & V4L2_SUBDEV_FL_STREAMS; int rval; switch (cmd) { @@ -466,7 +520,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, memset(cap->reserved, 0, sizeof(cap->reserved)); cap->version = LINUX_VERSION_CODE; - cap->capabilities = ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0; + cap->capabilities = + (ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0) | + (streams_subdev ? V4L2_SUBDEV_CAP_STREAMS : 0); return 0; } @@ -757,6 +813,81 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, case VIDIOC_SUBDEV_QUERYSTD: return v4l2_subdev_call(sd, video, querystd, arg); + case VIDIOC_SUBDEV_G_ROUTING: { + struct v4l2_subdev_routing *routing = arg; + struct v4l2_subdev_krouting *krouting; + + if (!v4l2_subdev_enable_streams_api) + return -ENOIOCTLCMD; + + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) + return -ENOIOCTLCMD; + + memset(routing->reserved, 0, sizeof(routing->reserved)); + + krouting = &state->routing; + + if (routing->num_routes < krouting->num_routes) { + routing->num_routes = krouting->num_routes; + return -ENOSPC; + } + + memcpy((struct v4l2_subdev_route *)(uintptr_t)routing->routes, + krouting->routes, + krouting->num_routes * sizeof(*krouting->routes)); + routing->num_routes = krouting->num_routes; + + return 0; + } + + case VIDIOC_SUBDEV_S_ROUTING: { + struct v4l2_subdev_routing *routing = arg; + struct v4l2_subdev_route *routes = + (struct v4l2_subdev_route *)(uintptr_t)routing->routes; + struct v4l2_subdev_krouting krouting = {}; + unsigned int i; + + if (!v4l2_subdev_enable_streams_api) + return -ENOIOCTLCMD; + + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) + return -ENOIOCTLCMD; + + if (routing->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev) + return -EPERM; + + memset(routing->reserved, 0, sizeof(routing->reserved)); + + for (i = 0; i < routing->num_routes; ++i) { + const struct v4l2_subdev_route *route = &routes[i]; + const struct media_pad *pads = sd->entity.pads; + + if (route->sink_stream > V4L2_SUBDEV_MAX_STREAM_ID || + route->source_stream > V4L2_SUBDEV_MAX_STREAM_ID) + return -EINVAL; + + if (route->sink_pad >= sd->entity.num_pads) + return -EINVAL; + + if (!(pads[route->sink_pad].flags & + MEDIA_PAD_FL_SINK)) + return -EINVAL; + + if (route->source_pad >= sd->entity.num_pads) + return -EINVAL; + + if (!(pads[route->source_pad].flags & + MEDIA_PAD_FL_SOURCE)) + return -EINVAL; + } + + krouting.num_routes = routing->num_routes; + krouting.routes = routes; + + return v4l2_subdev_call(sd, pad, set_routing, state, + routing->which, &krouting); + } + default: return v4l2_subdev_call(sd, core, ioctl, cmd, arg); } @@ -937,7 +1068,7 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); static int -v4l2_subdev_link_validate_get_format(struct media_pad *pad, +v4l2_subdev_link_validate_get_format(struct media_pad *pad, u32 stream, struct v4l2_subdev_format *fmt) { if (is_media_entity_v4l2_subdev(pad->entity)) { @@ -946,7 +1077,11 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; fmt->pad = pad->index; - return v4l2_subdev_call_state_active(sd, pad, get_fmt, fmt); + fmt->stream = stream; + + return v4l2_subdev_call(sd, pad, get_fmt, + v4l2_subdev_get_locked_active_state(sd), + fmt); } WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L, @@ -956,34 +1091,206 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, return -EINVAL; } +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + +static void __v4l2_link_validate_get_streams(struct media_pad *pad, + u64 *streams_mask) +{ + struct v4l2_subdev_route *route; + struct v4l2_subdev_state *state; + struct v4l2_subdev *subdev; + + subdev = media_entity_to_v4l2_subdev(pad->entity); + + *streams_mask = 0; + + state = v4l2_subdev_get_locked_active_state(subdev); + if (WARN_ON(!state)) + return; + + for_each_active_route(&state->routing, route) { + u32 route_pad; + u32 route_stream; + + if (pad->flags & MEDIA_PAD_FL_SOURCE) { + route_pad = route->source_pad; + route_stream = route->source_stream; + } else { + route_pad = route->sink_pad; + route_stream = route->sink_stream; + } + + if (route_pad != pad->index) + continue; + + *streams_mask |= BIT_ULL(route_stream); + } +} + +#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */ + +static void v4l2_link_validate_get_streams(struct media_pad *pad, + u64 *streams_mask) +{ + struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(pad->entity); + + if (!(subdev->flags & V4L2_SUBDEV_FL_STREAMS)) { + /* Non-streams subdevs have an implicit stream 0 */ + *streams_mask = BIT_ULL(0); + return; + } + +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + __v4l2_link_validate_get_streams(pad, streams_mask); +#else + /* This shouldn't happen */ + *streams_mask = 0; +#endif +} + +static int v4l2_subdev_link_validate_locked(struct media_link *link) +{ + struct v4l2_subdev *sink_subdev = + media_entity_to_v4l2_subdev(link->sink->entity); + struct device *dev = sink_subdev->entity.graph_obj.mdev->dev; + u64 source_streams_mask; + u64 sink_streams_mask; + u64 dangling_sink_streams; + u32 stream; + int ret; + + dev_dbg(dev, "validating link \"%s\":%u -> \"%s\":%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + v4l2_link_validate_get_streams(link->source, &source_streams_mask); + v4l2_link_validate_get_streams(link->sink, &sink_streams_mask); + + /* + * It is ok to have more source streams than sink streams as extra + * source streams can just be ignored by the receiver, but having extra + * sink streams is an error as streams must have a source. + */ + dangling_sink_streams = (source_streams_mask ^ sink_streams_mask) & + sink_streams_mask; + if (dangling_sink_streams) { + dev_err(dev, "Dangling sink streams: mask %#llx\n", + dangling_sink_streams); + return -EINVAL; + } + + /* Validate source and sink stream formats */ + + for (stream = 0; stream < sizeof(sink_streams_mask) * 8; ++stream) { + struct v4l2_subdev_format sink_fmt, source_fmt; + + if (!(sink_streams_mask & BIT_ULL(stream))) + continue; + + dev_dbg(dev, "validating stream \"%s\":%u:%u -> \"%s\":%u:%u\n", + link->source->entity->name, link->source->index, stream, + link->sink->entity->name, link->sink->index, stream); + + ret = v4l2_subdev_link_validate_get_format(link->source, stream, + &source_fmt); + if (ret < 0) { + dev_dbg(dev, + "Failed to get format for \"%s\":%u:%u (but that's ok)\n", + link->source->entity->name, link->source->index, + stream); + continue; + } + + ret = v4l2_subdev_link_validate_get_format(link->sink, stream, + &sink_fmt); + if (ret < 0) { + dev_dbg(dev, + "Failed to get format for \"%s\":%u:%u (but that's ok)\n", + link->sink->entity->name, link->sink->index, + stream); + continue; + } + + /* TODO: add stream number to link_validate() */ + ret = v4l2_subdev_call(sink_subdev, pad, link_validate, link, + &source_fmt, &sink_fmt); + if (!ret) + continue; + + if (ret != -ENOIOCTLCMD) + return ret; + + ret = v4l2_subdev_link_validate_default(sink_subdev, link, + &source_fmt, &sink_fmt); + + if (ret) + return ret; + } + + return 0; +} + int v4l2_subdev_link_validate(struct media_link *link) { - struct v4l2_subdev *sink; - struct v4l2_subdev_format sink_fmt, source_fmt; - int rval; + struct v4l2_subdev *source_sd, *sink_sd; + struct v4l2_subdev_state *source_state, *sink_state; + int ret; - rval = v4l2_subdev_link_validate_get_format( - link->source, &source_fmt); - if (rval < 0) - return 0; + sink_sd = media_entity_to_v4l2_subdev(link->sink->entity); + source_sd = media_entity_to_v4l2_subdev(link->source->entity); - rval = v4l2_subdev_link_validate_get_format( - link->sink, &sink_fmt); - if (rval < 0) - return 0; + sink_state = v4l2_subdev_get_unlocked_active_state(sink_sd); + source_state = v4l2_subdev_get_unlocked_active_state(source_sd); - sink = media_entity_to_v4l2_subdev(link->sink->entity); + if (sink_state) + v4l2_subdev_lock_state(sink_state); - rval = v4l2_subdev_call(sink, pad, link_validate, link, - &source_fmt, &sink_fmt); - if (rval != -ENOIOCTLCMD) - return rval; + if (source_state) + v4l2_subdev_lock_state(source_state); + + ret = v4l2_subdev_link_validate_locked(link); - return v4l2_subdev_link_validate_default( - sink, link, &source_fmt, &sink_fmt); + if (sink_state) + v4l2_subdev_unlock_state(sink_state); + + if (source_state) + v4l2_subdev_unlock_state(source_state); + + return ret; } EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); +bool v4l2_subdev_has_pad_interdep(struct media_entity *entity, + unsigned int pad0, unsigned int pad1) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct v4l2_subdev_krouting *routing; + struct v4l2_subdev_state *state; + unsigned int i; + + state = v4l2_subdev_lock_and_get_active_state(sd); + + routing = &state->routing; + + for (i = 0; i < routing->num_routes; ++i) { + struct v4l2_subdev_route *route = &routing->routes[i]; + + if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) + continue; + + if ((route->sink_pad == pad0 && route->source_pad == pad1) || + (route->source_pad == pad0 && route->sink_pad == pad1)) { + v4l2_subdev_unlock_state(state); + return true; + } + } + + v4l2_subdev_unlock_state(state); + + return false; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_has_pad_interdep); + struct v4l2_subdev_state * __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name, struct lock_class_key *lock_key) @@ -1001,7 +1308,8 @@ __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name, else state->lock = &state->_lock; - if (sd->entity.num_pads) { + /* Drivers that support streams do not need the legacy pad config */ + if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS) && sd->entity.num_pads) { state->pads = kvcalloc(sd->entity.num_pads, sizeof(*state->pads), GFP_KERNEL); if (!state->pads) { @@ -1040,6 +1348,8 @@ void __v4l2_subdev_state_free(struct v4l2_subdev_state *state) mutex_destroy(&state->_lock); + kfree(state->routing.routes); + kvfree(state->stream_configs.configs); kvfree(state->pads); kfree(state); } @@ -1069,15 +1379,68 @@ EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup); #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) +static int +v4l2_subdev_init_stream_configs(struct v4l2_subdev_stream_configs *stream_configs, + const struct v4l2_subdev_krouting *routing) +{ + struct v4l2_subdev_stream_configs new_configs = { 0 }; + struct v4l2_subdev_route *route; + u32 idx; + + /* Count number of formats needed */ + for_each_active_route(routing, route) { + /* + * Each route needs a format on both ends of the route. + */ + new_configs.num_configs += 2; + } + + if (new_configs.num_configs) { + new_configs.configs = kvcalloc(new_configs.num_configs, + sizeof(*new_configs.configs), + GFP_KERNEL); + + if (!new_configs.configs) + return -ENOMEM; + } + + /* + * Fill in the 'pad' and stream' value for each item in the array from + * the routing table + */ + idx = 0; + + for_each_active_route(routing, route) { + new_configs.configs[idx].pad = route->sink_pad; + new_configs.configs[idx].stream = route->sink_stream; + + idx++; + + new_configs.configs[idx].pad = route->source_pad; + new_configs.configs[idx].stream = route->source_stream; + + idx++; + } + + kvfree(stream_configs->configs); + *stream_configs = new_configs; + + return 0; +} + int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt; - if (format->pad >= sd->entity.num_pads) - return -EINVAL; + if (sd->flags & V4L2_SUBDEV_FL_STREAMS) + fmt = v4l2_subdev_state_get_stream_format(state, format->pad, + format->stream); + else if (format->pad < sd->entity.num_pads && format->stream == 0) + fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); + else + fmt = NULL; - fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); if (!fmt) return -EINVAL; @@ -1087,6 +1450,590 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, } EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt); +int v4l2_subdev_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + const struct v4l2_subdev_krouting *routing) +{ + struct v4l2_subdev_krouting *dst = &state->routing; + const struct v4l2_subdev_krouting *src = routing; + struct v4l2_subdev_krouting new_routing = { 0 }; + size_t bytes; + int r; + + if (unlikely(check_mul_overflow((size_t)src->num_routes, + sizeof(*src->routes), &bytes))) + return -EOVERFLOW; + + lockdep_assert_held(state->lock); + + if (src->num_routes > 0) { + new_routing.routes = kmemdup(src->routes, bytes, GFP_KERNEL); + if (!new_routing.routes) + return -ENOMEM; + } + + new_routing.num_routes = src->num_routes; + + r = v4l2_subdev_init_stream_configs(&state->stream_configs, + &new_routing); + if (r) { + kfree(new_routing.routes); + return r; + } + + kfree(dst->routes); + *dst = new_routing; + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing); + +struct v4l2_subdev_route * +__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing, + struct v4l2_subdev_route *route) +{ + if (route) + ++route; + else + route = &routing->routes[0]; + + for (; route < routing->routes + routing->num_routes; ++route) { + if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) + continue; + + return route; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(__v4l2_subdev_next_active_route); + +int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing, + const struct v4l2_mbus_framefmt *fmt) +{ + struct v4l2_subdev_stream_configs *stream_configs; + unsigned int i; + int ret; + + ret = v4l2_subdev_set_routing(sd, state, routing); + if (ret) + return ret; + + stream_configs = &state->stream_configs; + + for (i = 0; i < stream_configs->num_configs; ++i) + stream_configs->configs[i].fmt = *fmt; + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing_with_fmt); + +struct v4l2_mbus_framefmt * +v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream) +{ + struct v4l2_subdev_stream_configs *stream_configs; + unsigned int i; + + lockdep_assert_held(state->lock); + + stream_configs = &state->stream_configs; + + for (i = 0; i < stream_configs->num_configs; ++i) { + if (stream_configs->configs[i].pad == pad && + stream_configs->configs[i].stream == stream) + return &stream_configs->configs[i].fmt; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_format); + +struct v4l2_rect * +v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream) +{ + struct v4l2_subdev_stream_configs *stream_configs; + unsigned int i; + + lockdep_assert_held(state->lock); + + stream_configs = &state->stream_configs; + + for (i = 0; i < stream_configs->num_configs; ++i) { + if (stream_configs->configs[i].pad == pad && + stream_configs->configs[i].stream == stream) + return &stream_configs->configs[i].crop; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_crop); + +struct v4l2_rect * +v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream) +{ + struct v4l2_subdev_stream_configs *stream_configs; + unsigned int i; + + lockdep_assert_held(state->lock); + + stream_configs = &state->stream_configs; + + for (i = 0; i < stream_configs->num_configs; ++i) { + if (stream_configs->configs[i].pad == pad && + stream_configs->configs[i].stream == stream) + return &stream_configs->configs[i].compose; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_compose); + +int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, + u32 pad, u32 stream, u32 *other_pad, + u32 *other_stream) +{ + unsigned int i; + + for (i = 0; i < routing->num_routes; ++i) { + struct v4l2_subdev_route *route = &routing->routes[i]; + + if (route->source_pad == pad && + route->source_stream == stream) { + if (other_pad) + *other_pad = route->sink_pad; + if (other_stream) + *other_stream = route->sink_stream; + return 0; + } + + if (route->sink_pad == pad && route->sink_stream == stream) { + if (other_pad) + *other_pad = route->source_pad; + if (other_stream) + *other_stream = route->source_stream; + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_routing_find_opposite_end); + +struct v4l2_mbus_framefmt * +v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state, + u32 pad, u32 stream) +{ + u32 other_pad, other_stream; + int ret; + + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, + pad, stream, + &other_pad, &other_stream); + if (ret) + return NULL; + + return v4l2_subdev_state_get_stream_format(state, other_pad, + other_stream); +} +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_opposite_stream_format); + +u64 v4l2_subdev_state_xlate_streams(const struct v4l2_subdev_state *state, + u32 pad0, u32 pad1, u64 *streams) +{ + const struct v4l2_subdev_krouting *routing = &state->routing; + struct v4l2_subdev_route *route; + u64 streams0 = 0; + u64 streams1 = 0; + + for_each_active_route(routing, route) { + if (route->sink_pad == pad0 && route->source_pad == pad1 && + (*streams & BIT_ULL(route->sink_stream))) { + streams0 |= BIT_ULL(route->sink_stream); + streams1 |= BIT_ULL(route->source_stream); + } + if (route->source_pad == pad0 && route->sink_pad == pad1 && + (*streams & BIT_ULL(route->source_stream))) { + streams0 |= BIT_ULL(route->source_stream); + streams1 |= BIT_ULL(route->sink_stream); + } + } + + *streams = streams0; + return streams1; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_state_xlate_streams); + +int v4l2_subdev_routing_validate(struct v4l2_subdev *sd, + const struct v4l2_subdev_krouting *routing, + enum v4l2_subdev_routing_restriction disallow) +{ + u32 *remote_pads = NULL; + unsigned int i, j; + int ret = -EINVAL; + + if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) { + remote_pads = kcalloc(sd->entity.num_pads, sizeof(*remote_pads), + GFP_KERNEL); + if (!remote_pads) + return -ENOMEM; + + for (i = 0; i < sd->entity.num_pads; ++i) + remote_pads[i] = U32_MAX; + } + + for (i = 0; i < routing->num_routes; ++i) { + const struct v4l2_subdev_route *route = &routing->routes[i]; + + /* Validate the sink and source pad numbers. */ + if (route->sink_pad >= sd->entity.num_pads || + !(sd->entity.pads[route->sink_pad].flags & MEDIA_PAD_FL_SINK)) { + dev_dbg(sd->dev, "route %u sink (%u) is not a sink pad\n", + i, route->sink_pad); + goto out; + } + + if (route->source_pad >= sd->entity.num_pads || + !(sd->entity.pads[route->source_pad].flags & MEDIA_PAD_FL_SOURCE)) { + dev_dbg(sd->dev, "route %u source (%u) is not a source pad\n", + i, route->source_pad); + goto out; + } + + /* + * V4L2_SUBDEV_ROUTING_NO_STREAM_MIX: Streams on the same pad + * may not be routed to streams on different pads. + */ + if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) { + if (remote_pads[route->sink_pad] != U32_MAX && + remote_pads[route->sink_pad] != route->source_pad) { + dev_dbg(sd->dev, + "route %u attempts to mix %s streams\n", + i, "sink"); + goto out; + } + + if (remote_pads[route->source_pad] != U32_MAX && + remote_pads[route->source_pad] != route->sink_pad) { + dev_dbg(sd->dev, + "route %u attempts to mix %s streams\n", + i, "source"); + goto out; + } + + remote_pads[route->sink_pad] = route->source_pad; + remote_pads[route->source_pad] = route->sink_pad; + } + + for (j = i + 1; j < routing->num_routes; ++j) { + const struct v4l2_subdev_route *r = &routing->routes[j]; + + /* + * V4L2_SUBDEV_ROUTING_NO_1_TO_N: No two routes can + * originate from the same (sink) stream. + */ + if ((disallow & V4L2_SUBDEV_ROUTING_NO_1_TO_N) && + route->sink_pad == r->sink_pad && + route->sink_stream == r->sink_stream) { + dev_dbg(sd->dev, + "routes %u and %u originate from same sink (%u/%u)\n", + i, j, route->sink_pad, + route->sink_stream); + goto out; + } + + /* + * V4L2_SUBDEV_ROUTING_NO_N_TO_1: No two routes can end + * at the same (source) stream. + */ + if ((disallow & V4L2_SUBDEV_ROUTING_NO_N_TO_1) && + route->source_pad == r->source_pad && + route->source_stream == r->source_stream) { + dev_dbg(sd->dev, + "routes %u and %u end at same source (%u/%u)\n", + i, j, route->source_pad, + route->source_stream); + goto out; + } + } + } + + ret = 0; + +out: + kfree(remote_pads); + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_routing_validate); + +static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) +{ + struct device *dev = sd->entity.graph_obj.mdev->dev; + unsigned int i; + int ret; + + /* + * The subdev doesn't implement pad-based stream enable, fall back + * on the .s_stream() operation. This can only be done for subdevs that + * have a single source pad, as sd->enabled_streams is global to the + * subdev. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + + for (i = 0; i < sd->entity.num_pads; ++i) { + if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) + return -EOPNOTSUPP; + } + + if (sd->enabled_streams & streams_mask) { + dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n", + streams_mask, sd->entity.name, pad); + return -EALREADY; + } + + /* Start streaming when the first streams are enabled. */ + if (!sd->enabled_streams) { + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret) + return ret; + } + + sd->enabled_streams |= streams_mask; + + return 0; +} + +int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) +{ + struct device *dev = sd->entity.graph_obj.mdev->dev; + struct v4l2_subdev_state *state; + u64 found_streams = 0; + unsigned int i; + int ret; + + /* A few basic sanity checks first. */ + if (pad >= sd->entity.num_pads) + return -EINVAL; + + if (!streams_mask) + return 0; + + /* Fallback on .s_stream() if .enable_streams() isn't available. */ + if (!sd->ops->pad || !sd->ops->pad->enable_streams) + return v4l2_subdev_enable_streams_fallback(sd, pad, + streams_mask); + + state = v4l2_subdev_lock_and_get_active_state(sd); + + /* + * Verify that the requested streams exist and that they are not + * already enabled. + */ + for (i = 0; i < state->stream_configs.num_configs; ++i) { + struct v4l2_subdev_stream_config *cfg = + &state->stream_configs.configs[i]; + + if (cfg->pad != pad || !(streams_mask & BIT_ULL(cfg->stream))) + continue; + + found_streams |= BIT_ULL(cfg->stream); + + if (cfg->enabled) { + dev_dbg(dev, "stream %u already enabled on %s:%u\n", + cfg->stream, sd->entity.name, pad); + ret = -EALREADY; + goto done; + } + } + + if (found_streams != streams_mask) { + dev_dbg(dev, "streams 0x%llx not found on %s:%u\n", + streams_mask & ~found_streams, sd->entity.name, pad); + ret = -EINVAL; + goto done; + } + + /* Call the .enable_streams() operation. */ + ret = v4l2_subdev_call(sd, pad, enable_streams, state, pad, + streams_mask); + if (ret) + goto done; + + /* Mark the streams as enabled. */ + for (i = 0; i < state->stream_configs.num_configs; ++i) { + struct v4l2_subdev_stream_config *cfg = + &state->stream_configs.configs[i]; + + if (cfg->pad == pad && (streams_mask & BIT_ULL(cfg->stream))) + cfg->enabled = true; + } + +done: + v4l2_subdev_unlock_state(state); + + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_enable_streams); + +static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) +{ + struct device *dev = sd->entity.graph_obj.mdev->dev; + unsigned int i; + int ret; + + /* + * If the subdev doesn't implement pad-based stream enable, fall back + * on the .s_stream() operation. This can only be done for subdevs that + * have a single source pad, as sd->enabled_streams is global to the + * subdev. + */ + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; + + for (i = 0; i < sd->entity.num_pads; ++i) { + if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) + return -EOPNOTSUPP; + } + + if ((sd->enabled_streams & streams_mask) != streams_mask) { + dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n", + streams_mask, sd->entity.name, pad); + return -EALREADY; + } + + /* Stop streaming when the last streams are disabled. */ + if (!(sd->enabled_streams & ~streams_mask)) { + ret = v4l2_subdev_call(sd, video, s_stream, 0); + if (ret) + return ret; + } + + sd->enabled_streams &= ~streams_mask; + + return 0; +} + +int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask) +{ + struct device *dev = sd->entity.graph_obj.mdev->dev; + struct v4l2_subdev_state *state; + u64 found_streams = 0; + unsigned int i; + int ret; + + /* A few basic sanity checks first. */ + if (pad >= sd->entity.num_pads) + return -EINVAL; + + if (!streams_mask) + return 0; + + /* Fallback on .s_stream() if .disable_streams() isn't available. */ + if (!sd->ops->pad || !sd->ops->pad->disable_streams) + return v4l2_subdev_disable_streams_fallback(sd, pad, + streams_mask); + + state = v4l2_subdev_lock_and_get_active_state(sd); + + /* + * Verify that the requested streams exist and that they are not + * already disabled. + */ + for (i = 0; i < state->stream_configs.num_configs; ++i) { + struct v4l2_subdev_stream_config *cfg = + &state->stream_configs.configs[i]; + + if (cfg->pad != pad || !(streams_mask & BIT_ULL(cfg->stream))) + continue; + + found_streams |= BIT_ULL(cfg->stream); + + if (!cfg->enabled) { + dev_dbg(dev, "stream %u already disabled on %s:%u\n", + cfg->stream, sd->entity.name, pad); + ret = -EALREADY; + goto done; + } + } + + if (found_streams != streams_mask) { + dev_dbg(dev, "streams 0x%llx not found on %s:%u\n", + streams_mask & ~found_streams, sd->entity.name, pad); + ret = -EINVAL; + goto done; + } + + /* Call the .disable_streams() operation. */ + ret = v4l2_subdev_call(sd, pad, disable_streams, state, pad, + streams_mask); + if (ret) + goto done; + + /* Mark the streams as disabled. */ + for (i = 0; i < state->stream_configs.num_configs; ++i) { + struct v4l2_subdev_stream_config *cfg = + &state->stream_configs.configs[i]; + + if (cfg->pad == pad && (streams_mask & BIT_ULL(cfg->stream))) + cfg->enabled = false; + } + +done: + v4l2_subdev_unlock_state(state); + + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_disable_streams); + +int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable) +{ + struct v4l2_subdev_state *state; + struct v4l2_subdev_route *route; + struct media_pad *pad; + u64 source_mask = 0; + int pad_index = -1; + + /* + * Find the source pad. This helper is meant for subdevs that have a + * single source pad, so failures shouldn't happen, but catch them + * loudly nonetheless as they indicate a driver bug. + */ + media_entity_for_each_pad(&sd->entity, pad) { + if (pad->flags & MEDIA_PAD_FL_SOURCE) { + pad_index = pad->index; + break; + } + } + + if (WARN_ON(pad_index == -1)) + return -EINVAL; + + /* + * As there's a single source pad, just collect all the source streams. + */ + state = v4l2_subdev_lock_and_get_active_state(sd); + + for_each_active_route(&state->routing, route) + source_mask |= BIT_ULL(route->source_stream); + + v4l2_subdev_unlock_state(state); + + if (enable) + return v4l2_subdev_enable_streams(sd, pad_index, source_mask); + else + return v4l2_subdev_disable_streams(sd, pad_index, source_mask); +} +EXPORT_SYMBOL_GPL(v4l2_subdev_s_stream_helper); + #endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */ #endif /* CONFIG_MEDIA_CONTROLLER */ diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 617012e09a37..bc6c7b248f86 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -22,6 +22,8 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/atomisp/Kconfig" +source "drivers/staging/media/av7110/Kconfig" + source "drivers/staging/media/imx/Kconfig" source "drivers/staging/media/ipu3/Kconfig" @@ -52,13 +54,6 @@ menuconfig STAGING_MEDIA_DEPRECATED if STAGING_MEDIA_DEPRECATED source "drivers/staging/media/deprecated/atmel/Kconfig" -source "drivers/staging/media/deprecated/cpia2/Kconfig" -source "drivers/staging/media/deprecated/fsl-viu/Kconfig" -source "drivers/staging/media/deprecated/meye/Kconfig" -source "drivers/staging/media/deprecated/saa7146/Kconfig" -source "drivers/staging/media/deprecated/stkwebcam/Kconfig" -source "drivers/staging/media/deprecated/tm6000/Kconfig" -source "drivers/staging/media/deprecated/zr364xx/Kconfig" endif endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 1e14edc2d44c..1a4c3a062e3d 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,18 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VIDEO_ATMEL_ISC_BASE) += deprecated/atmel/ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ -obj-$(CONFIG_VIDEO_CPIA2) += deprecated/cpia2/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ -obj-$(CONFIG_VIDEO_MEYE) += deprecated/meye/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ -obj-$(CONFIG_VIDEO_STKWEBCAM) += deprecated/stkwebcam/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ -obj-$(CONFIG_VIDEO_TM6000) += deprecated/tm6000/ -obj-$(CONFIG_VIDEO_VIU) += deprecated/fsl-viu/ -obj-$(CONFIG_USB_ZR364XX) += deprecated/zr364xx/ -obj-y += deprecated/saa7146/ +obj-$(CONFIG_DVB_AV7110) += av7110/ diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index 2c8d7fdcc5f7..c9bff98e5309 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -14,7 +14,7 @@ config VIDEO_ATOMISP depends on VIDEO_DEV && INTEL_ATOMISP depends on PMIC_OPREGION select IOSF_MBI - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC select VIDEO_V4L2_SUBDEV_API help Say Y here if your platform supports Intel Atom SoC diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 87a634bf9ff5..0d90683ed227 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -241,179 +241,6 @@ static int gc0310_write_reg_array(struct i2c_client *client, return __gc0310_flush_reg_array(client, &ctrl); } -static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM; - return 0; -} - -static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) | - (GC0310_F_NUMBER_DEM << 16) | - (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM; - return 0; -} - -static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = dev->res->bin_factor_x; - - return 0; -} - -static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = dev->res->bin_factor_y; - - return 0; -} - -static int gc0310_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc0310_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 val; - u8 reg_val; - int ret; - unsigned int hori_blanking; - unsigned int vert_blanking; - unsigned int sh_delay; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz; - dev_dbg(&client->dev, "vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); - - /* get integration time */ - buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC0310_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC0310_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - /* Getting crop_horizontal_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "crop_horizontal_start=%d\n", buf->crop_horizontal_start); - - /* Getting crop_vertical_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "crop_vertical_start=%d\n", buf->crop_vertical_start); - - /* Getting output_width */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "output_width=%d\n", buf->output_width); - - /* Getting output_height */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = val | (reg_val & 0xFF); - dev_dbg(&client->dev, "output_height=%d\n", buf->output_height); - - buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1; - dev_dbg(&client->dev, "crop_horizontal_end=%d\n", buf->crop_horizontal_end); - dev_dbg(&client->dev, "crop_vertical_end=%d\n", buf->crop_vertical_end); - - /* Getting line_length_pck */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_L, ®_val); - if (ret) - return ret; - hori_blanking = val | (reg_val & 0xFF); - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SH_DELAY, ®_val); - if (ret) - return ret; - sh_delay = reg_val; - buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4; - dev_dbg(&client->dev, "hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, - sh_delay, buf->line_length_pck); - - /* Getting frame_length_lines */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_L, ®_val); - if (ret) - return ret; - vert_blanking = val | (reg_val & 0xFF); - buf->frame_length_lines = buf->output_height + vert_blanking; - dev_dbg(&client->dev, "vert_blanking=%d frame_length_lines=%d\n", vert_blanking, - buf->frame_length_lines); - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) { @@ -596,21 +423,6 @@ static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = gc0310_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc0310_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc0310_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val); - break; default: ret = -EINVAL; } @@ -655,61 +467,6 @@ static const struct v4l2_ctrl_config gc0310_controls[] = { .step = 1, .def = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC0310_FOCAL_LENGTH_DEFAULT, - .max = GC0310_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC0310_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC0310_F_NUMBER_DEFAULT, - .max = GC0310_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC0310_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC0310_F_NUMBER_RANGE, - .max = GC0310_F_NUMBER_RANGE, - .step = 0x01, - .def = GC0310_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, }; static int gc0310_init(struct v4l2_subdev *sd) @@ -952,12 +709,6 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd, goto err; } - ret = gc0310_get_intg_factor(client, gc0310_info, dev->res); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - err: mutex_unlock(&dev->input_lock); return ret; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 4d5a7e335f85..cb4c79b483ca 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -220,135 +220,6 @@ static int gc2235_write_reg_array(struct i2c_client *client, return __gc2235_flush_reg_array(client, &ctrl); } -static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /* const f number for imx */ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM; - return 0; -} - -static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) | - (GC2235_F_NUMBER_DEM << 16) | - (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM; - return 0; -} - -static int gc2235_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc2235_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 reg_val, reg_val_h; - int ret; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000; - - /* get integration time */ - buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC2235_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC2235_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_horizontal_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_vertical_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = (reg_val_h << 8) | reg_val; - - buf->crop_horizontal_end = buf->crop_horizontal_start + - buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + - buf->output_height - 1; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_L, ®_val); - if (ret) - return ret; - -#if 0 - u16 dummy = (reg_val_h << 8) | reg_val; -#endif - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_L, ®_val); - -#if 0 - buf->line_length_pck = buf->output_width + 16 + dummy + - (((u16)reg_val_h << 8) | (u16)reg_val) + 4; -#endif - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_L, ®_val); - if (ret) - return ret; - -#if 0 - buf->frame_length_lines = buf->output_height + 32 + - (((u16)reg_val_h << 8) | (u16)reg_val); -#endif - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -467,15 +338,6 @@ static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = gc2235_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc2235_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc2235_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val); - break; default: ret = -EINVAL; } @@ -499,39 +361,6 @@ static struct v4l2_ctrl_config gc2235_controls[] = { .def = 0x00, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC2235_FOCAL_LENGTH_DEFAULT, - .max = GC2235_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC2235_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC2235_F_NUMBER_DEFAULT, - .max = GC2235_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC2235_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC2235_F_NUMBER_RANGE, - .max = GC2235_F_NUMBER_RANGE, - .step = 0x01, - .def = GC2235_F_NUMBER_RANGE, - .flags = 0, - }, }; static int __gc2235_init(struct v4l2_subdev *sd) @@ -743,11 +572,6 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd, goto err; } - ret = gc2235_get_intg_factor(client, gc2235_info, - dev->res); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - err: mutex_unlock(&dev->input_lock); return ret; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index a0e8e94b2412..0e5a981dd331 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -612,96 +612,6 @@ static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size) return 0; } -static int mt9m114_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct mt9m114_res_struct *res) -{ - struct atomisp_sensor_mode_data *buf; - u32 reg_val; - int ret; - - if (!info) - return -EINVAL; - - buf = &info->data; - - ret = mt9m114_read_reg(client, MISENSOR_32BIT, - REG_PIXEL_CLK, ®_val); - if (ret) - return ret; - buf->vt_pix_clk_freq_mhz = reg_val; - - /* get integration time */ - buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - MT9M114_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - MT9M114_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN; - - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_START, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_START, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_END, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_END, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_WIDTH, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_HEIGHT, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_HTS, ®_val); - if (ret) - return ret; - buf->line_length_pck = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_VTS, ®_val); - if (ret) - return ret; - buf->frame_length_lines = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static int mt9m114_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -823,12 +733,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, mt9m114_res[index].used = false; } } - ret = mt9m114_get_intg_factor(c, mt9m114_info, - &mt9m114_res[res->res]); - if (ret) { - dev_err(&c->dev, "failed to get integration_factor\n"); - return -EINVAL; - } /* * mt9m114 - we don't poll for context switch * because it does not happen with streaming disabled. @@ -841,28 +745,6 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, return 0; } -/* TODO: Update to SOC functions, remove exposure and gain */ -static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM; - return 0; -} - -static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /* const f number for mt9m114 */ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM; - return 0; -} - -static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) | - (MT9M114_F_NUMBER_DEM << 16) | - (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM; - return 0; -} - /* Horizontal flip the image. */ static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val) { @@ -1134,24 +1016,6 @@ static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, return 0; } -static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_x; - - return 0; -} - -static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_y; - - return 0; -} - static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val) { struct i2c_client *c = v4l2_get_subdevdata(sd); @@ -1271,27 +1135,12 @@ static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_HFLIP: ret = mt9m114_g_hflip(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = mt9m114_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_EXPOSURE_ABSOLUTE: ret = mt9m114_g_exposure(&dev->sd, &ctrl->val); break; case V4L2_CID_EXPOSURE_ZONE_NUM: ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val); - break; case V4L2_CID_EXPOSURE: ret = mt9m114_g_ev(&dev->sd, &ctrl->val); break; @@ -1333,39 +1182,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { }, { .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .name = "focal length", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_FOCAL_LENGTH_DEFAULT, - .max = MT9M114_FOCAL_LENGTH_DEFAULT, - .step = 1, - .def = MT9M114_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .name = "f-number", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_DEFAULT, - .max = MT9M114_F_NUMBER_DEFAULT, - .step = 1, - .def = MT9M114_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .name = "f-number range", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_RANGE, - .max = MT9M114_F_NUMBER_RANGE, - .step = 1, - .def = MT9M114_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, .id = V4L2_CID_EXPOSURE_ABSOLUTE, .name = "exposure", .type = V4L2_CTRL_TYPE_INTEGER, @@ -1399,28 +1215,6 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { }, { .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .name = "horizontal binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .name = "vertical binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, .id = V4L2_CID_EXPOSURE, .name = "exposure biasx", .type = V4L2_CTRL_TYPE_INTEGER, diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index fa1de45b7a2d..aeb38599fe13 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -15,30 +15,22 @@ * */ -#include <asm/unaligned.h> - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/kmod.h> +#include <linux/acpi.h> #include <linux/device.h> -#include <linux/delay.h> -#include <linux/slab.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> #include <linux/i2c.h> -#include <linux/moduleparam.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/types.h> + +#include <media/ov_16bit_addr_reg_helpers.h> #include <media/v4l2-device.h> -#include <linux/io.h> -#include <linux/acpi.h> + #include "../include/linux/atomisp_gmin_platform.h" #include "ov2680.h" -static int h_flag; -static int v_flag; static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { atomisp_bayer_order_bggr, atomisp_bayer_order_grbg, @@ -46,64 +38,6 @@ static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { atomisp_bayer_order_rggb, }; -/* i2c read/write stuff */ -static int ov2680_read_reg(struct i2c_client *client, - int len, u16 reg, u32 *val) -{ - struct i2c_msg msgs[2]; - u8 addr_buf[2] = { reg >> 8, reg & 0xff }; - u8 data_buf[4] = { 0, }; - int ret; - - if (len > 4) - return -EINVAL; - - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_buf[4 - len]; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) { - dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret); - return -EIO; - } - - *val = get_unaligned_be32(data_buf); - - return 0; -} - -static int ov2680_write_reg(struct i2c_client *client, unsigned int len, - u16 reg, u16 val) -{ - u8 buf[6]; - int ret; - - if (len == 2) - put_unaligned_be16(val, buf + 2); - else if (len == 1) - buf[2] = val; - else - return -EINVAL; - - put_unaligned_be16(reg, buf); - - ret = i2c_master_send(client, buf, len + 2); - if (ret != len + 2) { - dev_err(&client->dev, "write error %d reg 0x%04x, val 0x%02x: buf sent: %*ph\n", - ret, reg, val, len + 2, &buf); - return -EIO; - } - - return 0; -} - static int ov2680_write_reg_array(struct i2c_client *client, const struct ov2680_reg *reglist) { @@ -111,7 +45,7 @@ static int ov2680_write_reg_array(struct i2c_client *client, int ret; for (; next->reg != 0; next++) { - ret = ov2680_write_reg(client, 1, next->reg, next->val); + ret = ov_write_reg8(client, next->reg, next->val); if (ret) return ret; } @@ -119,518 +53,127 @@ static int ov2680_write_reg_array(struct i2c_client *client, return 0; } -static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) +static void ov2680_set_bayer_order(struct ov2680_device *sensor, struct v4l2_mbus_framefmt *fmt) { - /* const f number for ov2680 */ - - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; - return 0; -} + static const int ov2680_hv_flip_bayer_order[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + }; + struct camera_mipi_info *ov2680_info; + int hv_flip = 0; -static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) | - (OV2680_F_NUMBER_DEM << 16) | - (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM; - return 0; -} + if (sensor->ctrls.vflip->val) + hv_flip += 1; -static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); + if (sensor->ctrls.hflip->val) + hv_flip += 2; - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n"); - *val = dev->res->bin_factor_x; + fmt->code = ov2680_hv_flip_bayer_order[hv_flip]; - return 0; + /* TODO atomisp specific custom API, should be removed */ + ov2680_info = v4l2_get_subdev_hostdata(&sensor->sd); + if (ov2680_info) + ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[hv_flip]; } -static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +static int ov2680_set_vflip(struct ov2680_device *sensor, s32 val) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - *val = dev->res->bin_factor_y; - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n"); - return 0; -} - -static int ov2680_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2680_resolution *res) -{ - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u32 reg_val; int ret; - dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n"); - if (!info) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2680_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2680_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; + if (sensor->is_streaming) + return -EBUSY; - ret = ov2680_read_reg(client, 2, - OV2680_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT1, BIT(2), val ? BIT(2) : 0); + if (ret < 0) return ret; - buf->output_width = reg_val; - ret = ov2680_read_reg(client, 2, - OV2680_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - (res->bin_factor_x * 2) : 1; - buf->binning_factor_y = res->bin_factor_y ? - (res->bin_factor_y * 2) : 1; + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); return 0; } -static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - +static int ov2680_set_hflip(struct ov2680_device *sensor, s32 val) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2680_device *dev = to_ov2680_sensor(sd); - u16 vts; - int ret, exp_val; - - dev_dbg(&client->dev, - "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n", - coarse_itg, gain, digitgain); - - vts = dev->res->lines_per_frame; - - /* group hold */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_GROUP_ACCESS); - return ret; - } - - /* Increase the VTS to match exposure + MARGIN */ - if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN) - vts = (u16)coarse_itg + OV2680_INTEGRATION_TIME_MARGIN; - - ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_TIMING_VTS_H); - return ret; - } - - /* set exposure */ - - /* Lower four bit should be 0*/ - exp_val = coarse_itg << 4; - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_L); - return ret; - } - - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_M); - return ret; - } - - ret = ov2680_write_reg(client, 1, - OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov2680_write_reg(client, 2, OV2680_AGC_H, gain); - if (ret) { - dev_err(&client->dev, "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_AGC_H); - return ret; - } - /* Digital gain */ - if (digitgain) { - ret = ov2680_write_reg(client, 2, - OV2680_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, 2, - OV2680_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, 2, - OV2680_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, - "%s: write 0x%02x: error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - } + int ret; - /* End group */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0x10); - if (ret) - return ret; + if (sensor->is_streaming) + return -EBUSY; - /* Delay launch group */ - ret = ov2680_write_reg(client, 1, - OV2680_GROUP_ACCESS, 0xa0); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_FORMAT2, BIT(2), val ? BIT(2) : 0); + if (ret < 0) return ret; - return ret; -} - -static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - int ret = 0; - - mutex_lock(&dev->input_lock); - - dev->exposure = exposure; - dev->gain = gain; - dev->digitgain = digitgain; - if (dev->power_on) - ret = __ov2680_set_exposure(sd, exposure, gain, digitgain); - - mutex_unlock(&dev->input_lock); - - return ret; + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); + return 0; } -static long ov2680_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) +static int ov2680_exposure_set(struct ov2680_device *sensor, u32 exp) { - u16 coarse_itg = exposure->integration_time[0]; - u16 analog_gain = exposure->gain[0]; - u16 digital_gain = exposure->gain[1]; - - /* we should not accept the invalid value below */ - if (analog_gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain); + return ov_write_reg24(sensor->client, OV2680_REG_EXPOSURE_PK_HIGH, exp << 4); } -static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +static int ov2680_gain_set(struct ov2680_device *sensor, u32 gain) { - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov2680_s_exposure(sd, arg); - - default: - return -EINVAL; - } - return 0; + return ov_write_reg16(sensor->client, OV2680_REG_GAIN_PK, gain); } -/* - * This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) +static int ov2680_test_pattern_set(struct ov2680_device *sensor, int value) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 reg_val; int ret; - /* get exposure */ - ret = ov2680_read_reg(client, 3, OV2680_EXPOSURE_H, ®_val); - if (ret) - return ret; - - /* Lower four bits are not part of the exposure val (always 0) */ - *value = reg_val >> 4; - return 0; -} + if (!value) + return ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), 0); -static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) -{ - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u32 val; - u8 index; - - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, 0x03, value - 1); + if (ret < 0) return ret; - if (value) - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - else - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - ret = ov2680_write_reg(client, 1, - OV2680_FLIP_REG, val); - if (ret) + ret = ov_update_reg(sensor->client, OV2680_REG_ISP_CTRL00, BIT(7), BIT(7)); + if (ret < 0) return ret; - index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT : - 0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; - } - return ret; + + return 0; } -static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) +static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) { - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct ov2680_device *sensor = to_ov2680_sensor(sd); int ret; - u32 val; - u8 index; - - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - - ret = ov2680_read_reg(client, 1, OV2680_MIRROR_REG, &val); - if (ret) - return ret; - if (value) - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - else - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - ret = ov2680_write_reg(client, 1, - OV2680_MIRROR_REG, val); - if (ret) - return ret; - index = (v_flag > 0 ? OV2680_FLIP_BIT : 0) | (h_flag > 0 ? OV2680_MIRROR_BIT : - 0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; + /* Only apply changes to the controls if the device is powered up */ + if (!pm_runtime_get_if_in_use(sensor->sd.dev)) { + ov2680_set_bayer_order(sensor, &sensor->mode.fmt); + return 0; } - return ret; -} - -static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; switch (ctrl->id) { case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_v_flip(&dev->sd, ctrl->val); + ret = ov2680_set_vflip(sensor, ctrl->val); break; case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_h_flip(&dev->sd, ctrl->val); + ret = ov2680_set_hflip(sensor, ctrl->val); break; - default: - ret = -EINVAL; - } - return ret; -} - -static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov2680_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2680_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2680_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val); + case V4L2_CID_EXPOSURE: + ret = ov2680_exposure_set(sensor, ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); + case V4L2_CID_GAIN: + ret = ov2680_gain_set(sensor, ctrl->val); break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val); + case V4L2_CID_TEST_PATTERN: + ret = ov2680_test_pattern_set(sensor, ctrl->val); break; default: ret = -EINVAL; } + pm_runtime_put(sensor->sd.dev); return ret; } -static const struct v4l2_ctrl_ops ctrl_ops = { +static const struct v4l2_ctrl_ops ov2680_ctrl_ops = { .s_ctrl = ov2680_s_ctrl, - .g_volatile_ctrl = ov2680_g_volatile_ctrl -}; - -static const struct v4l2_ctrl_config ov2680_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2680_FOCAL_LENGTH_DEFAULT, - .max = OV2680_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2680_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2680_F_NUMBER_DEFAULT, - .max = OV2680_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2680_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2680_F_NUMBER_RANGE, - .max = OV2680_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2680_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, }; static int ov2680_init_registers(struct v4l2_subdev *sd) @@ -638,288 +181,191 @@ static int ov2680_init_registers(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - ret = ov2680_write_reg(client, 1, OV2680_SW_RESET, 0x01); + ret = ov_write_reg8(client, OV2680_SW_RESET, 0x01); ret |= ov2680_write_reg_array(client, ov2680_global_setting); return ret; } -static int power_ctrl(struct v4l2_subdev *sd, bool flag) +static struct v4l2_mbus_framefmt * +__ov2680_get_pad_format(struct ov2680_device *sensor, + struct v4l2_subdev_state *state, + unsigned int pad, enum v4l2_subdev_format_whence which) { - int ret = 0; - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - dev_dbg(&client->dev, "%s: %s", __func__, flag ? "on" : "off"); - - if (flag) { - ret |= dev->platform_data->v1p8_ctrl(sd, 1); - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - usleep_range(10000, 15000); - } + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&sensor->sd, state, pad); - if (!flag || ret) { - ret |= dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; + return &sensor->mode.fmt; } -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +static void ov2680_fill_format(struct ov2680_device *sensor, + struct v4l2_mbus_framefmt *fmt, + unsigned int width, unsigned int height) { - int ret; - struct ov2680_device *dev = to_ov2680_sensor(sd); + memset(fmt, 0, sizeof(*fmt)); + fmt->width = width; + fmt->height = height; + fmt->field = V4L2_FIELD_NONE; + ov2680_set_bayer_order(sensor, fmt); +} - if (!dev || !dev->platform_data) - return -ENODEV; +static void ov2680_calc_mode(struct ov2680_device *sensor, int width, int height) +{ + int orig_width = width; + int orig_height = height; - /* - * The OV2680 documents only one GPIO input (#XSHUTDN), but - * existing integrations often wire two (reset/power_down) - * because that is the way other sensors work. There is no - * way to tell how it is wired internally, so existing - * firmwares expose both and we drive them symmetrically. - */ - if (flag) { - ret = dev->platform_data->gpio0_ctrl(sd, 1); - usleep_range(10000, 15000); - /* Ignore return from second gpio, it may not be there */ - dev->platform_data->gpio1_ctrl(sd, 1); - usleep_range(10000, 15000); + if (width <= (OV2680_NATIVE_WIDTH / 2) && + height <= (OV2680_NATIVE_HEIGHT / 2)) { + sensor->mode.binning = true; + width *= 2; + height *= 2; } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->gpio0_ctrl(sd, 0); + sensor->mode.binning = false; } - return ret; + + sensor->mode.h_start = ((OV2680_NATIVE_WIDTH - width) / 2) & ~1; + sensor->mode.v_start = ((OV2680_NATIVE_HEIGHT - height) / 2) & ~1; + sensor->mode.h_end = min(sensor->mode.h_start + width + OV2680_END_MARGIN - 1, + OV2680_NATIVE_WIDTH - 1); + sensor->mode.v_end = min(sensor->mode.v_start + height + OV2680_END_MARGIN - 1, + OV2680_NATIVE_HEIGHT - 1); + sensor->mode.h_output_size = orig_width; + sensor->mode.v_output_size = orig_height; + sensor->mode.hts = OV2680_PIXELS_PER_LINE; + sensor->mode.vts = OV2680_LINES_PER_FRAME; } -static int power_up(struct v4l2_subdev *sd) +static int ov2680_set_mode(struct ov2680_device *sensor) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct i2c_client *client = sensor->client; + u8 pll_div, unknown, inc, fmt1, fmt2; int ret; - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; + if (sensor->mode.binning) { + pll_div = 1; + unknown = 0x23; + inc = 0x31; + fmt1 = 0xc2; + fmt2 = 0x01; + } else { + pll_div = 0; + unknown = 0x21; + inc = 0x11; + fmt1 = 0xc0; + fmt2 = 0x00; } - if (dev->power_on) - return 0; /* Already on */ - - /* power control */ - ret = power_ctrl(sd, 1); + ret = ov_write_reg8(client, 0x3086, pll_div); if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } + return ret; - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); + ret = ov_write_reg8(client, 0x370a, unknown); if (ret) - goto fail_clk; - - /* according to DS, 20ms is needed between PWDN and i2c access */ - msleep(20); + return ret; - ret = ov2680_init_registers(sd); + ret = ov_write_reg16(client, OV2680_HORIZONTAL_START_H, sensor->mode.h_start); if (ret) - goto fail_init_registers; + return ret; - ret = __ov2680_set_exposure(sd, dev->exposure, dev->gain, dev->digitgain); + ret = ov_write_reg16(client, OV2680_VERTICAL_START_H, sensor->mode.v_start); if (ret) - goto fail_init_registers; + return ret; - dev->power_on = true; - return 0; + ret = ov_write_reg16(client, OV2680_HORIZONTAL_END_H, sensor->mode.h_end); + if (ret) + return ret; -fail_init_registers: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); + ret = ov_write_reg16(client, OV2680_VERTICAL_END_H, sensor->mode.v_end); + if (ret) + return ret; - return ret; -} + ret = ov_write_reg16(client, OV2680_HORIZONTAL_OUTPUT_SIZE_H, + sensor->mode.h_output_size); + if (ret) + return ret; -static int power_down(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; + ret = ov_write_reg16(client, OV2680_VERTICAL_OUTPUT_SIZE_H, + sensor->mode.v_output_size); + if (ret) + return ret; - h_flag = 0; - v_flag = 0; - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } + ret = ov_write_reg16(client, OV2680_HTS, sensor->mode.hts); + if (ret) + return ret; - if (!dev->power_on) - return 0; /* Already off */ + ret = ov_write_reg16(client, OV2680_VTS, sensor->mode.vts); + if (ret) + return ret; - ret = dev->platform_data->flisclk_ctrl(sd, 0); + ret = ov_write_reg16(client, OV2680_ISP_X_WIN, 0); if (ret) - dev_err(&client->dev, "flisclk failed\n"); + return ret; - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } + ret = ov_write_reg16(client, OV2680_ISP_Y_WIN, 0); + if (ret) + return ret; - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) { - dev_err(&client->dev, "vprog failed.\n"); + ret = ov_write_reg8(client, OV2680_X_INC, inc); + if (ret) return ret; - } - dev->power_on = false; - return 0; -} + ret = ov_write_reg8(client, OV2680_Y_INC, inc); + if (ret) + return ret; -static int ov2680_s_power(struct v4l2_subdev *sd, int on) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - int ret; + ret = ov_write_reg16(client, OV2680_X_WIN, sensor->mode.h_output_size); + if (ret) + return ret; - mutex_lock(&dev->input_lock); + ret = ov_write_reg16(client, OV2680_Y_WIN, sensor->mode.v_output_size); + if (ret) + return ret; - if (on == 0) { - ret = power_down(sd); - } else { - ret = power_up(sd); - } + ret = ov_write_reg8(client, OV2680_REG_FORMAT1, fmt1); + if (ret) + return ret; - mutex_unlock(&dev->input_lock); + ret = ov_write_reg8(client, OV2680_REG_FORMAT2, fmt2); + if (ret) + return ret; - return ret; + return 0; } static int ov2680_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov2680_info = NULL; - struct ov2680_resolution *res; - int vts, ret = 0; - - dev_dbg(&client->dev, "%s: %s: pad: %d, fmt: %p\n", - __func__, - (format->which == V4L2_SUBDEV_FORMAT_TRY) ? "try" : "set", - format->pad, fmt); - - if (format->pad) - return -EINVAL; + struct ov2680_device *sensor = to_ov2680_sensor(sd); + struct v4l2_mbus_framefmt *fmt; + unsigned int width, height; - if (!fmt) - return -EINVAL; + width = min_t(unsigned int, ALIGN(format->format.width, 2), OV2680_NATIVE_WIDTH); + height = min_t(unsigned int, ALIGN(format->format.height, 2), OV2680_NATIVE_HEIGHT); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (!ov2680_info) - return -EINVAL; + fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which); + ov2680_fill_format(sensor, fmt, width, height); - res = v4l2_find_nearest_size(ov2680_res_preview, - ARRAY_SIZE(ov2680_res_preview), width, - height, fmt->width, fmt->height); - if (!res) - res = &ov2680_res_preview[N_RES_PREVIEW - 1]; + format->format = *fmt; - fmt->width = res->width; - fmt->height = res->height; - - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sd_state->pads->try_fmt = *fmt; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - } - - dev_dbg(&client->dev, "%s: %dx%d\n", - __func__, fmt->width, fmt->height); - mutex_lock(&dev->input_lock); - - /* s_power has not been called yet for std v4l2 clients (camorama) */ - power_up(sd); - ret = ov2680_write_reg_array(client, dev->res->regs); - if (ret) { - dev_err(&client->dev, - "ov2680 write resolution register err: %d\n", ret); - goto err; - } - - vts = dev->res->lines_per_frame; - - /* If necessary increase the VTS to match exposure + MARGIN */ - if (dev->exposure > vts - OV2680_INTEGRATION_TIME_MARGIN) - vts = dev->exposure + OV2680_INTEGRATION_TIME_MARGIN; - - ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts); - if (ret) { - dev_err(&client->dev, "ov2680 write vts err: %d\n", ret); - goto err; - } - - ret = ov2680_get_intg_factor(client, ov2680_info, res); - if (ret) { - dev_err(&client->dev, "failed to get integration factor\n"); - goto err; - } - - /* - * recall flip functions to avoid flip registers - * were overridden by default setting - */ - if (h_flag) - ov2680_h_flip(sd, h_flag); - if (v_flag) - ov2680_v_flip(sd, v_flag); - - dev->res = res; -err: - mutex_unlock(&dev->input_lock); - return ret; + mutex_lock(&sensor->input_lock); + ov2680_calc_mode(sensor, fmt->width, fmt->height); + mutex_unlock(&sensor->input_lock); + return 0; } static int ov2680_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov2680_device *dev = to_ov2680_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = dev->res->width; - fmt->height = dev->res->height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + struct ov2680_device *sensor = to_ov2680_sensor(sd); + struct v4l2_mbus_framefmt *fmt; + fmt = __ov2680_get_pad_format(sensor, sd_state, format->pad, format->which); + format->format = *fmt; return 0; } @@ -934,14 +380,12 @@ static int ov2680_detect(struct i2c_client *client) if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_CHIP_ID_H, &high); + ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_H, &high); if (ret) { dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); return -ENODEV; } - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_CHIP_ID_L, &low); + ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_L, &low); id = ((((u16)high) << 8) | (u16)low); if (id != OV2680_ID) { @@ -949,8 +393,7 @@ static int ov2680_detect(struct i2c_client *client) return -ENODEV; } - ret = ov2680_read_reg(client, 1, - OV2680_SC_CMMN_SUB_ID, &high); + ret = ov_read_reg8(client, OV2680_SC_CMMN_SUB_ID, &high); revision = (u8)high & 0x0f; dev_info(&client->dev, "sensor_revision id = 0x%x, rev= %d\n", @@ -961,88 +404,79 @@ static int ov2680_detect(struct i2c_client *client) static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) { - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; + int ret = 0; + + mutex_lock(&sensor->input_lock); + + if (sensor->is_streaming == enable) { + dev_warn(&client->dev, "stream already %s\n", enable ? "started" : "stopped"); + goto error_unlock; + } + + if (enable) { + ret = pm_runtime_get_sync(sensor->sd.dev); + if (ret < 0) + goto error_unlock; + + ret = ov2680_set_mode(sensor); + if (ret) + goto error_power_down; - mutex_lock(&dev->input_lock); - if (enable) - dev_dbg(&client->dev, "ov2680_s_stream one\n"); - else - dev_dbg(&client->dev, "ov2680_s_stream off\n"); + /* Restore value of all ctrls */ + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + if (ret) + goto error_power_down; - ret = ov2680_write_reg(client, 1, OV2680_SW_STREAM, - enable ? OV2680_START_STREAMING : - OV2680_STOP_STREAMING); + ret = ov_write_reg8(client, OV2680_SW_STREAM, OV2680_START_STREAMING); + if (ret) + goto error_power_down; + } else { + ov_write_reg8(client, OV2680_SW_STREAM, OV2680_STOP_STREAMING); + pm_runtime_put(sensor->sd.dev); + } - //otp valid at stream on state - //if(!dev->otp_data) - // dev->otp_data = ov2680_otp_read(sd); + sensor->is_streaming = enable; + v4l2_ctrl_activate(sensor->ctrls.vflip, !enable); + v4l2_ctrl_activate(sensor->ctrls.hflip, !enable); - mutex_unlock(&dev->input_lock); + mutex_unlock(&sensor->input_lock); + return 0; +error_power_down: + pm_runtime_put(sensor->sd.dev); +error_unlock: + mutex_unlock(&sensor->input_lock); return ret; } -static int ov2680_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) +static int ov2680_s_config(struct v4l2_subdev *sd) { - struct ov2680_device *dev = to_ov2680_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); + int ret; - ret = power_up(sd); - if (ret) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { dev_err(&client->dev, "ov2680 power-up err.\n"); goto fail_power_on; } - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - /* config & detect sensor */ ret = ov2680_detect(client); - if (ret) { + if (ret) dev_err(&client->dev, "ov2680_detect err s_config.\n"); - goto fail_csi_cfg; - } - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); - mutex_unlock(&dev->input_lock); + pm_runtime_put(&client->dev); return ret; } static int ov2680_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - interval->interval.numerator = 1; - interval->interval.denominator = dev->res->fps; - + interval->interval.denominator = OV2680_FPS; return 0; } @@ -1050,7 +484,8 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - if (code->index >= MAX_FMTS) + /* We support only a single format */ + if (code->index) return -EINVAL; code->code = MEDIA_BUS_FMT_SBGGR10_1X10; @@ -1061,15 +496,25 @@ static int ov2680_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { + static const struct v4l2_frmsize_discrete ov2680_frame_sizes[] = { + { 1616, 1216 }, + { 1616, 1096 }, + { 1616, 916 }, + { 1456, 1096 }, + { 1296, 976 }, + { 1296, 736 }, + { 784, 592 }, + { 656, 496 }, + }; int index = fse->index; - if (index >= N_RES_PREVIEW) + if (index >= ARRAY_SIZE(ov2680_frame_sizes)) return -EINVAL; - fse->min_width = ov2680_res_preview[index].width; - fse->min_height = ov2680_res_preview[index].height; - fse->max_width = ov2680_res_preview[index].width; - fse->max_height = ov2680_res_preview[index].height; + fse->min_width = ov2680_frame_sizes[index].width; + fse->min_height = ov2680_frame_sizes[index].height; + fse->max_width = ov2680_frame_sizes[index].width; + fse->max_height = ov2680_frame_sizes[index].height; return 0; } @@ -1078,30 +523,18 @@ static int ov2680_enum_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { - struct v4l2_fract fract; - - if (fie->index >= N_RES_PREVIEW || - fie->width > ov2680_res_preview[0].width || - fie->height > ov2680_res_preview[0].height || - fie->which > V4L2_SUBDEV_FORMAT_ACTIVE) + /* Only 1 framerate */ + if (fie->index) return -EINVAL; - fract.denominator = ov2680_res_preview[fie->index].fps; - fract.numerator = 1; - - fie->interval = fract; - + fie->interval.numerator = 1; + fie->interval.denominator = OV2680_FPS; return 0; } static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) { - struct ov2680_device *dev = to_ov2680_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = dev->res->skip_frames; - mutex_unlock(&dev->input_lock); - + *frames = OV2680_SKIP_FRAMES; return 0; } @@ -1114,11 +547,6 @@ static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = { .g_skip_frames = ov2680_g_skip_frames, }; -static const struct v4l2_subdev_core_ops ov2680_core_ops = { - .s_power = ov2680_s_power, - .ioctl = ov2680_ioctl, -}; - static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { .enum_mbus_code = ov2680_enum_mbus_code, .enum_frame_size = ov2680_enum_frame_size, @@ -1128,98 +556,173 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { }; static const struct v4l2_subdev_ops ov2680_ops = { - .core = &ov2680_core_ops, .video = &ov2680_video_ops, .pad = &ov2680_pad_ops, .sensor = &ov2680_sensor_ops, }; +static int ov2680_init_controls(struct ov2680_device *sensor) +{ + static const char * const test_pattern_menu[] = { + "Disabled", + "Color Bars", + "Random Data", + "Square", + "Black Image", + }; + const struct v4l2_ctrl_ops *ops = &ov2680_ctrl_ops; + struct ov2680_ctrls *ctrls = &sensor->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + int exp_max = OV2680_LINES_PER_FRAME - OV2680_INTEGRATION_TIME_MARGIN; + + v4l2_ctrl_handler_init(hdl, 4); + + hdl->lock = &sensor->input_lock; + + ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, + 0, exp_max, 1, exp_max); + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 1023, 1, 250); + ctrls->test_pattern = + v4l2_ctrl_new_std_menu_items(hdl, + &ov2680_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(test_pattern_menu) - 1, + 0, 0, test_pattern_menu); + + ctrls->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + ctrls->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + if (hdl->error) + return hdl->error; + + sensor->sd.ctrl_handler = hdl; + return 0; +} + static void ov2680_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2680_device *dev = to_ov2680_sensor(sd); + struct ov2680_device *sensor = to_ov2680_sensor(sd); dev_dbg(&client->dev, "ov2680_remove...\n"); - dev->platform_data->csi_cfg(sd, 0); - + atomisp_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->ctrls.handler); + pm_runtime_disable(&client->dev); } +/* + * Unlike other sensors which have both a rest and powerdown input pins, + * the OV2680 only has a powerdown input. But some ACPI tables still list + * 2 GPIOs for the OV2680 and it is unclear which to use. So try to get + * up to 2 GPIOs (1 mandatory, 1 optional) and control them in sync. + */ +static const struct acpi_gpio_params ov2680_first_gpio = { 0, 0, true }; +static const struct acpi_gpio_params ov2680_second_gpio = { 1, 0, true }; + +static const struct acpi_gpio_mapping ov2680_gpio_mapping[] = { + { "powerdown-gpios", &ov2680_first_gpio, 1 }, + { "powerdown-alt-gpios", &ov2680_second_gpio, 1 }, + { }, +}; + static int ov2680_probe(struct i2c_client *client) { - struct ov2680_device *dev; + struct device *dev = &client->dev; + struct ov2680_device *sensor; int ret; - void *pdata; - unsigned int i; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) return -ENOMEM; - mutex_init(&dev->input_lock); + mutex_init(&sensor->input_lock); - dev->res = &ov2680_res_preview[0]; - dev->exposure = dev->res->lines_per_frame - OV2680_INTEGRATION_TIME_MARGIN; - dev->gain = 250; /* 0-2047 */ - v4l2_i2c_subdev_init(&dev->sd, client, &ov2680_ops); + sensor->client = client; + v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_ops); - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - if (!pdata) { - ret = -EINVAL; - goto out_free; - } - - ret = ov2680_s_config(&dev->sd, client->irq, pdata); + ret = devm_acpi_dev_add_driver_gpios(&client->dev, ov2680_gpio_mapping); if (ret) - goto out_free; + return ret; + + sensor->powerdown = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown)) + return dev_err_probe(dev, PTR_ERR(sensor->powerdown), "getting powerdown GPIO\n"); + + sensor->powerdown_alt = devm_gpiod_get_optional(dev, "powerdown-alt", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown_alt)) + return dev_err_probe(dev, PTR_ERR(sensor->powerdown_alt), "getting powerdown-alt GPIO\n"); - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + ret = ov2680_s_config(&sensor->sd); if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov2680_controls)); + return ret; + + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = ov2680_init_controls(sensor); if (ret) { ov2680_remove(client); return ret; } - for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i], - NULL); - - if (dev->ctrl_handler.error) { + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) { ov2680_remove(client); - return dev->ctrl_handler.error; + return ret; } - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; + ov2680_fill_format(sensor, &sensor->mode.fmt, OV2680_NATIVE_WIDTH, OV2680_NATIVE_HEIGHT); - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + ret = atomisp_register_sensor_no_gmin(&sensor->sd, 1, ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_bggr); if (ret) { ov2680_remove(client); - dev_dbg(&client->dev, "+++ remove ov2680\n"); + return ret; } - return ret; -out_free: - dev_dbg(&client->dev, "+++ out free\n"); - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; + + return 0; } +static int ov2680_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2680_device *sensor = to_ov2680_sensor(sd); + + gpiod_set_value_cansleep(sensor->powerdown, 1); + gpiod_set_value_cansleep(sensor->powerdown_alt, 1); + return 0; +} + +static int ov2680_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2680_device *sensor = to_ov2680_sensor(sd); + + /* according to DS, at least 5ms is needed after DOVDD (enabled by ACPI) */ + usleep_range(5000, 6000); + + gpiod_set_value_cansleep(sensor->powerdown, 0); + gpiod_set_value_cansleep(sensor->powerdown_alt, 0); + + /* according to DS, 20ms is needed between PWDN and i2c access */ + msleep(20); + + ov2680_init_registers(sd); + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ov2680_pm_ops, ov2680_suspend, ov2680_resume, NULL); + static const struct acpi_device_id ov2680_acpi_match[] = { {"XXOV2680"}, {"OVTI2680"}, @@ -1230,6 +733,7 @@ MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); static struct i2c_driver ov2680_driver = { .driver = { .name = "ov2680", + .pm = pm_sleep_ptr(&ov2680_pm_ops), .acpi_match_table = ov2680_acpi_match, }, .probe_new = ov2680_probe, diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 887b6f99f6ca..5d2e6e2e72f0 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -261,134 +261,6 @@ static int ov2722_write_reg_array(struct i2c_client *client, return __ov2722_flush_reg_array(client, &ctrl); } -static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM; - return 0; -} - -static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) | - (OV2722_F_NUMBER_DEM << 16) | - (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM; - return 0; -} - -static int ov2722_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2722_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2722_device *dev = NULL; - struct atomisp_sensor_mode_data *buf = &info->data; - const unsigned int ext_clk_freq_hz = 19200000; - const unsigned int pll_invariant_div = 10; - unsigned int pix_clk_freq_hz; - u16 pre_pll_clk_div; - u16 pll_multiplier; - u16 op_pix_clk_div; - u16 reg_val; - int ret; - - if (!info) - return -EINVAL; - - dev = to_ov2722_sensor(sd); - - /* pixel clock calculattion */ - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div); - if (ret) - return ret; - - pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4; - if (!pre_pll_clk_div) - return -EINVAL; - - pll_multiplier = pll_multiplier & 0x7f; - op_pix_clk_div = op_pix_clk_div & 0x03; - pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier - * op_pix_clk_div / pll_invariant_div; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2722_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2722_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -547,15 +419,6 @@ static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = ov2722_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2722_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2722_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_LINK_FREQ: val = dev->res->mipi_freq; if (val == 0) @@ -588,39 +451,6 @@ static const struct v4l2_ctrl_config ov2722_controls[] = { }, { .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2722_FOCAL_LENGTH_DEFAULT, - .max = OV2722_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2722_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2722_F_NUMBER_DEFAULT, - .max = OV2722_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2722_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2722_F_NUMBER_RANGE, - .max = OV2722_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2722_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, .id = V4L2_CID_LINK_FREQ, .name = "Link Frequency", .type = V4L2_CTRL_TYPE_INTEGER, @@ -682,10 +512,7 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) * before PWDN# when turning it on or off. */ ret = dev->platform_data->gpio0_ctrl(sd, flag); - /* - *ov2722 PWDN# active high when pull down,opposite to the convention - */ - ret |= dev->platform_data->gpio1_ctrl(sd, !flag); + ret |= dev->platform_data->gpio1_ctrl(sd, flag); return ret; } @@ -701,6 +528,9 @@ static int power_up(struct v4l2_subdev *sd) return -ENODEV; } + if (dev->power_on == 1) + return 0; /* Already on */ + /* power control */ ret = power_ctrl(sd, 1); if (ret) @@ -725,6 +555,7 @@ static int power_up(struct v4l2_subdev *sd) /* according to DS, 20ms is needed between PWDN and i2c access */ msleep(20); + dev->power_on = 1; return 0; fail_clk: @@ -748,6 +579,9 @@ static int power_down(struct v4l2_subdev *sd) return -ENODEV; } + if (dev->power_on == 0) + return 0; /* Already off */ + ret = dev->platform_data->flisclk_ctrl(sd, 0); if (ret) dev_err(&client->dev, "flisclk failed\n"); @@ -765,6 +599,7 @@ static int power_down(struct v4l2_subdev *sd) if (ret) dev_err(&client->dev, "vprog failed.\n"); + dev->power_on = 0; return ret; } @@ -824,7 +659,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, if (!ov2722_info) return -EINVAL; - mutex_lock(&dev->input_lock); res = v4l2_find_nearest_size(ov2722_res_preview, ARRAY_SIZE(ov2722_res_preview), width, height, fmt->width, fmt->height); @@ -838,10 +672,13 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { sd_state->pads->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); return 0; } + mutex_lock(&dev->input_lock); + + /* s_power has not been called yet for std v4l2 clients (camorama) */ + power_up(sd); dev->pixels_per_line = dev->res->pixels_per_line; dev->lines_per_frame = dev->res->lines_per_frame; @@ -875,10 +712,6 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, } } - ret = ov2722_get_intg_factor(client, ov2722_info, dev->res); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - err: mutex_unlock(&dev->input_lock); return ret; @@ -1137,6 +970,7 @@ static int ov2722_probe(struct i2c_client *client) return -ENOMEM; mutex_init(&dev->input_lock); + dev->power_on = -1; dev->res = &ov2722_res_preview[0]; v4l2_i2c_subdev_init(&dev->sd, client, &ov2722_ops); @@ -1168,6 +1002,7 @@ out_ctrl_handler_free: v4l2_ctrl_handler_free(&dev->ctrl_handler); out_free: + atomisp_gmin_remove_subdev(&dev->sd); v4l2_device_unregister_subdev(&dev->sd); kfree(dev); return ret; diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h index 4b9ce681bd93..cae480ae6fba 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.h +++ b/drivers/staging/media/atomisp/i2c/gc0310.h @@ -38,9 +38,6 @@ #define I2C_RETRY_COUNT 5 #define GC0310_FOCAL_LENGTH_NUM 278 /*2.78mm*/ -#define GC0310_FOCAL_LENGTH_DEM 100 -#define GC0310_F_NUMBER_DEFAULT_NUM 26 -#define GC0310_F_NUMBER_DEM 10 #define MAX_FMTS 1 @@ -126,9 +123,6 @@ struct gc0310_resolution { u32 skip_frames; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; }; @@ -149,7 +143,6 @@ struct gc0310_device { struct v4l2_ctrl_handler ctrl_handler; struct camera_sensor_platform_data *platform_data; - int vt_pix_clk_freq_mhz; struct gc0310_resolution *res; u8 type; bool power_on; @@ -390,9 +383,6 @@ static struct gc0310_resolution gc0310_res_preview[] = { .pixels_per_line = 0x0314, .lines_per_frame = 0x0213, #endif - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 2, .regs = gc0310_VGA_30fps, }, diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index 806be5dff7a5..55ea422291ba 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -44,9 +44,6 @@ #define I2C_RETRY_COUNT 5 #define GC2235_FOCAL_LENGTH_NUM 278 /*2.78mm*/ -#define GC2235_FOCAL_LENGTH_DEM 100 -#define GC2235_F_NUMBER_DEFAULT_NUM 26 -#define GC2235_F_NUMBER_DEM 10 #define MAX_FMTS 1 @@ -137,9 +134,6 @@ struct gc2235_resolution { u32 skip_frames; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; }; @@ -161,7 +155,6 @@ struct gc2235_device { struct gc2235_resolution *res; struct camera_sensor_platform_data *platform_data; - int vt_pix_clk_freq_mhz; u8 type; }; @@ -540,9 +533,6 @@ static struct gc2235_resolution gc2235_res_preview[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1068, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1600_900_30fps, }, @@ -556,9 +546,6 @@ static struct gc2235_resolution gc2235_res_preview[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1082_30fps, }, @@ -571,9 +558,6 @@ static struct gc2235_resolution gc2235_res_preview[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1216_30fps, }, @@ -597,9 +581,6 @@ static struct gc2235_resolution gc2235_res_still[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1068, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1600_900_30fps, }, @@ -612,9 +593,6 @@ static struct gc2235_resolution gc2235_res_still[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1082_30fps, }, @@ -627,9 +605,6 @@ static struct gc2235_resolution gc2235_res_still[] = { .used = 0, .pixels_per_line = 2132, .lines_per_frame = 1368, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1616_1216_30fps, }, @@ -648,9 +623,6 @@ static struct gc2235_resolution gc2235_res_video[] = { .used = 0, .pixels_per_line = 1828, .lines_per_frame = 888, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_1296_736_30fps, }, @@ -663,9 +635,6 @@ static struct gc2235_resolution gc2235_res_video[] = { .used = 0, .pixels_per_line = 1492, .lines_per_frame = 792, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, .skip_frames = 3, .regs = gc2235_960_640_30fps, }, diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h index bcce18b65fa6..b0cd1b724394 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.h +++ b/drivers/staging/media/atomisp/i2c/mt9m114.h @@ -136,9 +136,6 @@ #define MT9M114_BPAT_BGBGGRGR BIT(3) #define MT9M114_FOCAL_LENGTH_NUM 208 /*2.08mm*/ -#define MT9M114_FOCAL_LENGTH_DEM 100 -#define MT9M114_F_NUMBER_DEFAULT_NUM 24 -#define MT9M114_F_NUMBER_DEM 10 #define MT9M114_WAIT_STAT_TIMEOUT 100 #define MT9M114_FLICKER_MODE_50HZ 1 #define MT9M114_FLICKER_MODE_60HZ 2 @@ -319,9 +316,6 @@ struct mt9m114_res_struct { struct regval_list *regs; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; }; /* 2 bytes used for address: 256 bytes total */ @@ -353,9 +347,6 @@ static struct mt9m114_res_struct mt9m114_res[] = { .pixels_per_line = 0x0640, .lines_per_frame = 0x0307, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, }, { .desc = "848P", @@ -369,9 +360,6 @@ static struct mt9m114_res_struct mt9m114_res[] = { .pixels_per_line = 0x0640, .lines_per_frame = 0x03E8, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, }, { .desc = "960P", @@ -385,9 +373,6 @@ static struct mt9m114_res_struct mt9m114_res[] = { .pixels_per_line = 0x0644, /* consistent with regs arrays */ .lines_per_frame = 0x03E5, /* consistent with regs arrays */ - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, }, }; diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 7ab337b859ad..a37af0a74a53 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -32,53 +32,22 @@ #include "../include/linux/atomisp_platform.h" -/* Defines for register writes and register array processing */ -#define I2C_MSG_LENGTH 0x2 -#define I2C_RETRY_COUNT 5 +#define OV2680_NATIVE_WIDTH 1616 +#define OV2680_NATIVE_HEIGHT 1216 -#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ -#define OV2680_FOCAL_LENGTH_DEM 100 -#define OV2680_F_NUMBER_DEFAULT_NUM 24 -#define OV2680_F_NUMBER_DEM 10 +/* 1704 * 1294 * 30fps = 66MHz pixel clock */ +#define OV2680_PIXELS_PER_LINE 1704 +#define OV2680_LINES_PER_FRAME 1294 +#define OV2680_FPS 30 +#define OV2680_SKIP_FRAMES 3 -#define OV2680_BIN_FACTOR_MAX 4 +/* If possible send 16 extra rows / lines to the ISP as padding */ +#define OV2680_END_MARGIN 16 -#define MAX_FMTS 1 +#define OV2680_FOCAL_LENGTH_NUM 334 /*3.34mm*/ -/* sensor_mode_data read_mode adaptation */ -#define OV2680_READ_MODE_BINNING_ON 0x0400 -#define OV2680_READ_MODE_BINNING_OFF 0x00 -#define OV2680_INTEGRATION_TIME_MARGIN 8 - -#define OV2680_MAX_EXPOSURE_VALUE 0xFFF1 -#define OV2680_MAX_GAIN_VALUE 0xFF - -/* - * focal length bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define OV2680_FOCAL_LENGTH_DEFAULT 0x1B70064 - -/* - * current f-number bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define OV2680_F_NUMBER_DEFAULT 0x18000a - -/* - * f-number range bits definition: - * bits 31-24: max f-number numerator - * bits 23-16: max f-number denominator - * bits 15-8: min f-number numerator - * bits 7-0: min f-number denominator - */ -#define OV2680_F_NUMBER_RANGE 0x180a180a -#define OV2680_ID 0x2680 - -#define OV2680_FINE_INTG_TIME_MIN 0 -#define OV2680_FINE_INTG_TIME_MAX_MARGIN 0 -#define OV2680_COARSE_INTG_TIME_MIN 1 -#define OV2680_COARSE_INTG_TIME_MAX_MARGIN 6 +#define OV2680_INTEGRATION_TIME_MARGIN 8 +#define OV2680_ID 0x2680 /* * OV2680 System control registers @@ -92,74 +61,49 @@ #define OV2680_SC_CMMN_SCCB_ID 0x302B /* 0x300C*/ #define OV2680_SC_CMMN_SUB_ID 0x302A /* process, version*/ -#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/ - -#define OV2680_EXPOSURE_H 0x3500 /*Bit[3:0] Bit[19:16] of exposure, remaining 16 bits lies in Reg0x3501&Reg0x3502*/ -#define OV2680_EXPOSURE_M 0x3501 -#define OV2680_EXPOSURE_L 0x3502 -#define OV2680_AGC_H 0x350A /*Bit[1:0] means Bit[9:8] of gain*/ -#define OV2680_AGC_L 0x350B /*Bit[7:0] of gain*/ - -#define OV2680_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/ -#define OV2680_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/ -#define OV2680_VERTICAL_START_H 0x3802 /*Bit[11:8]*/ -#define OV2680_VERTICAL_START_L 0x3803 /*Bit[7:0]*/ -#define OV2680_HORIZONTAL_END_H 0x3804 /*Bit[11:8]*/ -#define OV2680_HORIZONTAL_END_L 0x3805 /*Bit[7:0]*/ -#define OV2680_VERTICAL_END_H 0x3806 /*Bit[11:8]*/ -#define OV2680_VERTICAL_END_L 0x3807 /*Bit[7:0]*/ -#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /*Bit[3:0]*/ -#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/ -#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/ -#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/ -#define OV2680_TIMING_HTS_H 0x380C /*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV2680_TIMING_HTS_L 0x380D /*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV2680_TIMING_VTS_H 0x380e /*High 8-bit, and low 8-bit HTS address is 0x380f*/ -#define OV2680_TIMING_VTS_L 0x380f /*High 8-bit, and low 8-bit HTS address is 0x380f*/ -#define OV2680_FRAME_OFF_NUM 0x4202 +#define OV2680_GROUP_ACCESS 0x3208 /*Bit[7:4] Group control, Bit[3:0] Group ID*/ + +#define OV2680_REG_EXPOSURE_PK_HIGH 0x3500 +#define OV2680_REG_GAIN_PK 0x350a + +#define OV2680_HORIZONTAL_START_H 0x3800 /* Bit[11:8] */ +#define OV2680_HORIZONTAL_START_L 0x3801 /* Bit[7:0] */ +#define OV2680_VERTICAL_START_H 0x3802 /* Bit[11:8] */ +#define OV2680_VERTICAL_START_L 0x3803 /* Bit[7:0] */ +#define OV2680_HORIZONTAL_END_H 0x3804 /* Bit[11:8] */ +#define OV2680_HORIZONTAL_END_L 0x3805 /* Bit[7:0] */ +#define OV2680_VERTICAL_END_H 0x3806 /* Bit[11:8] */ +#define OV2680_VERTICAL_END_L 0x3807 /* Bit[7:0] */ +#define OV2680_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /* Bit[11:8] */ +#define OV2680_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /* Bit[7:0] */ +#define OV2680_VERTICAL_OUTPUT_SIZE_H 0x380a /* Bit[11:8] */ +#define OV2680_VERTICAL_OUTPUT_SIZE_L 0x380b /* Bit[7:0] */ +#define OV2680_HTS 0x380c +#define OV2680_VTS 0x380e +#define OV2680_ISP_X_WIN 0x3810 +#define OV2680_ISP_Y_WIN 0x3812 +#define OV2680_X_INC 0x3814 +#define OV2680_Y_INC 0x3815 + +#define OV2680_FRAME_OFF_NUM 0x4202 /*Flip/Mirror*/ -#define OV2680_FLIP_REG 0x3820 -#define OV2680_MIRROR_REG 0x3821 -#define OV2680_FLIP_BIT 1 -#define OV2680_MIRROR_BIT 2 -#define OV2680_FLIP_MIRROR_BIT_ENABLE 4 +#define OV2680_REG_FORMAT1 0x3820 +#define OV2680_REG_FORMAT2 0x3821 #define OV2680_MWB_RED_GAIN_H 0x5004/*0x3400*/ #define OV2680_MWB_GREEN_GAIN_H 0x5006/*0x3402*/ #define OV2680_MWB_BLUE_GAIN_H 0x5008/*0x3404*/ -#define OV2680_MWB_GAIN_MAX 0x0fff - -#define OV2680_START_STREAMING 0x01 -#define OV2680_STOP_STREAMING 0x00 - -#define OV2680_INVALID_CONFIG 0xffffffff +#define OV2680_MWB_GAIN_MAX 0x0fff -struct regval_list { - u16 reg_num; - u8 value; -}; +#define OV2680_REG_ISP_CTRL00 0x5080 -struct ov2680_resolution { - const struct ov2680_reg *regs; - int res; - int width; - int height; - int fps; - int pix_clk_freq; - u32 skip_frames; - u16 pixels_per_line; - u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; -}; +#define OV2680_X_WIN 0x5704 +#define OV2680_Y_WIN 0x5706 +#define OV2680_WIN_CONTROL 0x5708 -struct ov2680_format { - u8 *desc; - u32 pixelformat; - struct ov2680_reg *regs; -}; +#define OV2680_START_STREAMING 0x01 +#define OV2680_STOP_STREAMING 0x00 /* * ov2680 device structure. @@ -168,13 +112,32 @@ struct ov2680_device { struct v4l2_subdev sd; struct media_pad pad; struct mutex input_lock; - struct v4l2_ctrl_handler ctrl_handler; - struct ov2680_resolution *res; - struct camera_sensor_platform_data *platform_data; - bool power_on; - u16 exposure; - u16 gain; - u16 digitgain; + struct i2c_client *client; + struct gpio_desc *powerdown; + struct gpio_desc *powerdown_alt; + bool is_streaming; + + struct ov2680_mode { + struct v4l2_mbus_framefmt fmt; + bool binning; + u16 h_start; + u16 v_start; + u16 h_end; + u16 v_end; + u16 h_output_size; + u16 v_output_size; + u16 hts; + u16 vts; + } mode; + + struct ov2680_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *test_pattern; + } ctrls; }; /** @@ -192,17 +155,13 @@ struct ov2680_reg { #define to_ov2680_sensor(x) container_of(x, struct ov2680_device, sd) -#define OV2680_MAX_WRITE_BUF_SIZE 30 +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ + struct ov2680_device *sensor = + container_of(ctrl->handler, struct ov2680_device, ctrls.handler); -struct ov2680_write_buffer { - u16 addr; - u8 data[OV2680_MAX_WRITE_BUF_SIZE]; -}; - -struct ov2680_write_ctrl { - int index; - struct ov2680_write_buffer buffer; -}; + return &sensor->sd; +} static struct ov2680_reg const ov2680_global_setting[] = { {0x0103, 0x01}, @@ -240,6 +199,8 @@ static struct ov2680_reg const ov2680_global_setting[] = { {0x3819, 0x04}, {0x4000, 0x81}, {0x4001, 0x40}, + {0x4008, 0x00}, + {0x4009, 0x03}, {0x4602, 0x02}, {0x481f, 0x36}, {0x4825, 0x36}, @@ -252,6 +213,8 @@ static struct ov2680_reg const ov2680_global_setting[] = { {0x5008, 0x04}, {0x5009, 0x00}, {0x5080, 0x00}, + {0x5081, 0x41}, + {0x5708, 0x01}, /* add for full size flip off and mirror off 2014/09/11 */ {0x3701, 0x64}, //add on 14/05/13 {0x3784, 0x0c}, //based OV2680_R1A_AM10.ovt add on 14/06/13 {0x5780, 0x3e}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13 @@ -276,642 +239,7 @@ static struct ov2680_reg const ov2680_global_setting[] = { {0x5793, 0x00}, {0x5794, 0x03}, //based OV2680_R1A_AM10.ovt,Adjust DPC setting (57xx) on 14/06/13 {0x0100, 0x00}, //stream off - - {} -}; - -/* - * 176x144 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_QCIF_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x05}, - {0x3805, 0xaf}, - {0x3806, 0x04}, - {0x3807, 0x47}, - {0x3808, 0x00}, - {0x3809, 0xC0}, - {0x380a, 0x00}, - {0x380b, 0xa0}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4000, 0x81}, - {0x4001, 0x40}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 352x288 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_CIF_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x03}, - {0x3805, 0x8f}, - {0x3806, 0x02}, - {0x3807, 0xe7}, - {0x3808, 0x01}, - {0x3809, 0x70}, - {0x380a, 0x01}, - {0x380b, 0x30}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, {} }; -/* - * 336x256 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_QVGA_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x03}, - {0x3805, 0x4f}, - {0x3806, 0x02}, - {0x3807, 0x87}, - {0x3808, 0x01}, - {0x3809, 0x50}, - {0x380a, 0x01}, - {0x380b, 0x00}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 656x496 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_656x496_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0xa0}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x05}, - {0x3805, 0xcf}, - {0x3806, 0x04}, - {0x3807, 0x67}, - {0x3808, 0x02}, - {0x3809, 0x90}, - {0x380a, 0x01}, - {0x380b, 0xf0}, - {0x380c, 0x06}, - {0x380d, 0xb0}, - {0x3810, 0x00}, - {0x3811, 0x04}, - {0x3812, 0x00}, - {0x3813, 0x04}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 720x592 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_720x592_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0x00}, // X_ADDR_START; - {0x3802, 0x00}, - {0x3803, 0x00}, // Y_ADDR_START; - {0x3804, 0x05}, - {0x3805, 0xaf}, // X_ADDR_END; - {0x3806, 0x04}, - {0x3807, 0xaf}, // Y_ADDR_END; - {0x3808, 0x02}, - {0x3809, 0xd0}, // X_OUTPUT_SIZE; - {0x380a, 0x02}, - {0x380b, 0x50}, // Y_OUTPUT_SIZE; - {0x380c, 0x06}, - {0x380d, 0xac}, // HTS; - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5708, 0x00}, - {0x5704, 0x02}, - {0x5705, 0xd0}, // X_WIN; - {0x5706, 0x02}, - {0x5707, 0x50}, // Y_WIN; - {0x3820, 0xc2}, // FLIP_FORMAT; - {0x3821, 0x01}, // MIRROR_FORMAT; - {0x5090, 0x00}, // PRE ISP CTRL16, default value is 0x0C; - // BIT[3]: Mirror order, BG or GB; - // BIT[2]: Flip order, BR or RB; - {0x5081, 0x41}, - {} -}; - -/* - * 800x600 30fps VBlanking 1lane 10Bit (binning) - */ -static struct ov2680_reg const ov2680_800x600_30fps[] = { - {0x3086, 0x01}, - {0x370a, 0x23}, - {0x3801, 0x00}, /* hstart 0 */ - {0x3802, 0x00}, - {0x3803, 0x00}, /* vstart 0 */ - {0x3804, 0x06}, - {0x3805, 0x4f}, /* hend 1615 */ - {0x3806, 0x04}, - {0x3807, 0xbf}, /* vend 1215 */ - {0x3808, 0x03}, - {0x3809, 0x20}, /* hsize 800 */ - {0x380a, 0x02}, - {0x380b, 0x58}, /* vsize 600 */ - {0x380c, 0x06}, - {0x380d, 0xac}, /* htotal 1708 */ - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x31}, - {0x3815, 0x31}, - {0x5708, 0x00}, - {0x5704, 0x03}, - {0x5705, 0x20}, - {0x5706, 0x02}, - {0x5707, 0x58}, - {0x3820, 0xc2}, - {0x3821, 0x01}, - {0x5090, 0x00}, - {0x4008, 0x00}, - {0x4009, 0x03}, - {0x5081, 0x41}, - {} -}; - -/* - * 720p=1280*720 30fps VBlanking 1lane 10Bit (no-Scaling) - */ -static struct ov2680_reg const ov2680_720p_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0xa0}, /* hstart 160 */ - {0x3802, 0x00}, - {0x3803, 0xf2}, /* vstart 242 */ - {0x3804, 0x05}, - {0x3805, 0xbf}, /* hend 1471 */ - {0x3806, 0x03}, - {0x3807, 0xdd}, /* vend 989 */ - {0x3808, 0x05}, - {0x3809, 0x10}, /* hsize 1296 */ - {0x380a, 0x02}, - {0x380b, 0xe0}, /* vsize 736 */ - {0x380c, 0x06}, - {0x380d, 0xa8}, /* htotal 1704 */ - {0x3810, 0x00}, - {0x3811, 0x08}, - {0x3812, 0x00}, - {0x3813, 0x06}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0c}, - {} -}; - -/* - * 1296x976 30fps VBlanking 1lane 10Bit(no-scaling) - */ -static struct ov2680_reg const ov2680_1296x976_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0xa0}, /* hstart 160 */ - {0x3802, 0x00}, - {0x3803, 0x78}, /* vstart 120 */ - {0x3804, 0x05}, - {0x3805, 0xbf}, /* hend 1471 */ - {0x3806, 0x04}, - {0x3807, 0x57}, /* vend 1111 */ - {0x3808, 0x05}, - {0x3809, 0x10}, /* hsize 1296 */ - {0x380a, 0x03}, - {0x380b, 0xd0}, /* vsize 976 */ - {0x380c, 0x06}, - {0x380d, 0xa8}, /* htotal 1704 */ - {0x3810, 0x00}, - {0x3811, 0x08}, - {0x3812, 0x00}, - {0x3813, 0x08}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, - {0x3820, 0xc0}, - {0x3821, 0x00}, //mirror/flip - // {0x5090, 0x0c}, - {} -}; - -/* - * 1456*1096 30fps VBlanking 1lane 10bit(no-scaling) - */ -static struct ov2680_reg const ov2680_1456x1096_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x90}, - {0x3802, 0x00}, - {0x3803, 0x78}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0xC0}, - {0x3808, 0x05}, - {0x3809, 0xb0}, - {0x380a, 0x04}, - {0x380b, 0x48}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x08}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x00}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x10}, - {0x5705, 0xa0}, - {0x5706, 0x0c}, - {0x5707, 0x78}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0c}, - {} -}; - -/* - *1616x916 30fps VBlanking 1lane 10bit - */ - -static struct ov2680_reg const ov2680_1616x916_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x00}, - {0x3802, 0x00}, - {0x3803, 0x96}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0x39}, - {0x3808, 0x06}, - {0x3809, 0x50}, - {0x380a, 0x03}, - {0x380b, 0x94}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x08}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x06}, - {0x5705, 0x50}, - {0x5706, 0x03}, - {0x5707, 0x94}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0C}, - {} -}; - -/* - * 1616x1082 30fps VBlanking 1lane 10Bit - */ -static struct ov2680_reg const ov2680_1616x1082_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x00}, - {0x3802, 0x00}, - {0x3803, 0x86}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0xbf}, - {0x3808, 0x06}, - {0x3809, 0x50}, - {0x380a, 0x04}, - {0x380b, 0x3a}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x06}, - {0x5705, 0x50}, - {0x5706, 0x04}, - {0x5707, 0x3a}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0C}, - {0x4008, 0x02}, - {0x4009, 0x09}, - {0x5081, 0x41}, - {} -}; - -/* - * 1616x1216 30fps VBlanking 1lane 10Bit - */ -static struct ov2680_reg const ov2680_1616x1216_30fps[] = { - {0x3086, 0x00}, - {0x370a, 0x21}, - {0x3801, 0x00}, - {0x3802, 0x00}, - {0x3803, 0x00}, - {0x3804, 0x06}, - {0x3805, 0x4f}, - {0x3806, 0x04}, - {0x3807, 0xbf}, - {0x3808, 0x06}, - {0x3809, 0x50},//50},//4line for mirror and flip - {0x380a, 0x04}, - {0x380b, 0xc0},//c0}, - {0x380c, 0x06}, - {0x380d, 0xa8}, - {0x3810, 0x00}, - {0x3811, 0x00}, - {0x3812, 0x00}, - {0x3813, 0x00}, - {0x3814, 0x11}, - {0x3815, 0x11}, - {0x4008, 0x00}, - {0x4009, 0x0b}, - {0x5081, 0x01}, - {0x5708, 0x01}, //add for full size flip off and mirror off 2014/09/11 - {0x5704, 0x06}, - {0x5705, 0x50}, - {0x5706, 0x04}, - {0x5707, 0xcc}, - {0x3820, 0xc0}, - {0x3821, 0x00}, - // {0x5090, 0x0C}, - {} -}; - -static struct ov2680_resolution ov2680_res_preview[] = { - { - .width = 1616, - .height = 1216, - .pix_clk_freq = 66, - .fps = 30, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1616x1216_30fps, - }, - { - .width = 1616, - .height = 1082, - .pix_clk_freq = 66, - .fps = 30, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1616x1082_30fps, - }, - { - .width = 1616, - .height = 916, - .fps = 30, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1616x916_30fps, - }, - { - .width = 1456, - .height = 1096, - .fps = 30, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1456x1096_30fps, - }, - { - .width = 1296, - .height = 976, - .fps = 30, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_1296x976_30fps, - }, - { - .width = 1296, - .height = 736, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_720p_30fps, - }, - { - .width = 800, - .height = 600, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_800x600_30fps, - }, - { - .width = 720, - .height = 592, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_720x592_30fps, - }, - { - .width = 656, - .height = 496, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_656x496_30fps, - }, - { - .width = 336, - .height = 256, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_QVGA_30fps, - }, - { - .width = 352, - .height = 288, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_CIF_30fps, - }, - { - .width = 176, - .height = 144, - .fps = 60, - .pix_clk_freq = 66, - .pixels_per_line = 1698,//1704, - .lines_per_frame = 1294, - .bin_factor_x = 0, - .bin_factor_y = 0, - .bin_mode = 0, - .skip_frames = 3, - .regs = ov2680_QCIF_30fps, - }, -}; - -#define N_RES_PREVIEW (ARRAY_SIZE(ov2680_res_preview)) - #endif diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index d6e2510bc01c..640d3ffcaa5c 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -39,9 +39,6 @@ #define I2C_RETRY_COUNT 5 #define OV2722_FOCAL_LENGTH_NUM 278 /*2.78mm*/ -#define OV2722_FOCAL_LENGTH_DEM 100 -#define OV2722_F_NUMBER_DEFAULT_NUM 26 -#define OV2722_F_NUMBER_DEM 10 #define MAX_FMTS 1 @@ -180,9 +177,6 @@ struct ov2722_resolution { u32 skip_frames; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; int mipi_freq; }; @@ -204,8 +198,7 @@ struct ov2722_device { struct ov2722_resolution *res; struct camera_sensor_platform_data *platform_data; - int vt_pix_clk_freq_mhz; - int run_mode; + int power_on; u16 pixels_per_line; u16 lines_per_frame; u8 type; @@ -1113,9 +1106,6 @@ static struct ov2722_resolution ov2722_res_preview[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1632_1092_30fps, .mipi_freq = 422400, @@ -1129,9 +1119,6 @@ static struct ov2722_resolution ov2722_res_preview[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1452_1092_30fps, .mipi_freq = 422400, @@ -1145,9 +1132,6 @@ static struct ov2722_resolution ov2722_res_preview[] = { .used = 0, .pixels_per_line = 2068, .lines_per_frame = 1114, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1080p_30fps, .mipi_freq = 345600, @@ -1171,9 +1155,6 @@ struct ov2722_resolution ov2722_res_still[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1632_1092_30fps, .mipi_freq = 422400, @@ -1187,9 +1168,6 @@ struct ov2722_resolution ov2722_res_still[] = { .used = 0, .pixels_per_line = 2260, .lines_per_frame = 1244, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1452_1092_30fps, .mipi_freq = 422400, @@ -1203,9 +1181,6 @@ struct ov2722_resolution ov2722_res_still[] = { .used = 0, .pixels_per_line = 2068, .lines_per_frame = 1114, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1080p_30fps, .mipi_freq = 345600, @@ -1224,9 +1199,6 @@ struct ov2722_resolution ov2722_res_video[] = { .used = 0, .pixels_per_line = 2048, .lines_per_frame = 1184, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_QVGA_30fps, .mipi_freq = 364800, @@ -1240,9 +1212,6 @@ struct ov2722_resolution ov2722_res_video[] = { .used = 0, .pixels_per_line = 2048, .lines_per_frame = 1184, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_480P_30fps, }, @@ -1255,9 +1224,6 @@ struct ov2722_resolution ov2722_res_video[] = { .used = 0, .pixels_per_line = 2068, .lines_per_frame = 1114, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .skip_frames = 3, .regs = ov2722_1080p_30fps, .mipi_freq = 345600, diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index c1cd631455e6..da8c3b1d3bcd 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -415,123 +415,6 @@ static int ov5693_write_reg_array(struct i2c_client *client, return __ov5693_flush_reg_array(client, &ctrl); } -static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM; - return 0; -} - -static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) | - (OV5693_F_NUMBER_DEM << 16) | - (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM; - return 0; -} - -static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_y; - - return 0; -} - -static int ov5693_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov5693_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u16 reg_val; - int ret; - - if (!info) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV5693_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV5693_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, int gain, int digitgain) @@ -1107,27 +990,12 @@ static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE_ABSOLUTE: ret = ov5693_q_exposure(&dev->sd, &ctrl->val); break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov5693_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov5693_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val); - break; case V4L2_CID_FOCUS_ABSOLUTE: ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val); break; case V4L2_CID_FOCUS_STATUS: ret = ov5693_q_focus_status(&dev->sd, &ctrl->val); break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val); - break; default: ret = -EINVAL; } @@ -1154,39 +1022,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = { }, { .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV5693_FOCAL_LENGTH_DEFAULT, - .max = OV5693_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV5693_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV5693_F_NUMBER_DEFAULT, - .max = OV5693_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV5693_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV5693_F_NUMBER_RANGE, - .max = OV5693_F_NUMBER_RANGE, - .step = 0x01, - .def = OV5693_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, .id = V4L2_CID_FOCUS_ABSOLUTE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "focus move absolute", @@ -1240,28 +1075,6 @@ static const struct v4l2_ctrl_config ov5693_controls[] = { .def = 0, .flags = 0, }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, }; static int ov5693_init(struct v4l2_subdev *sd) @@ -1659,18 +1472,10 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd, if (ret) dev_warn(&client->dev, "ov5693 stream off err\n"); - ret = ov5693_get_intg_factor(client, ov5693_info, - &ov5693_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - ov5693_info->metadata_width = fmt->width * 10 / 8; ov5693_info->metadata_height = 1; ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size; -err: mutex_unlock(&dev->input_lock); return ret; } diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h index a1366666f49c..5e17eaf8fd6e 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h @@ -198,9 +198,6 @@ struct ov5693_resolution { int pix_clk_freq; u16 pixels_per_line; u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; bool used; }; @@ -228,7 +225,6 @@ struct ov5693_device { struct camera_sensor_platform_data *platform_data; ktime_t timestamp_t_focus_abs; - int vt_pix_clk_freq_mhz; int fmt_idx; int run_mode; int otp_size; @@ -1110,9 +1106,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_736x496_30fps, }, { @@ -1124,9 +1117,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1616x1216_30fps, }, { @@ -1138,9 +1128,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2576x1456_30fps, }, { @@ -1152,9 +1139,6 @@ static struct ov5693_resolution ov5693_res_preview[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2576x1936_30fps, }, }; @@ -1176,9 +1160,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_736x496_30fps, }, { @@ -1190,9 +1171,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1424x1168_30fps, }, { @@ -1204,9 +1182,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1616x1216_30fps, }, { @@ -1218,9 +1193,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1456_30fps, }, { @@ -1232,9 +1204,6 @@ struct ov5693_resolution ov5693_res_still[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1944_30fps, }, }; @@ -1251,9 +1220,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_736x496, }, { @@ -1265,9 +1231,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_336x256, }, { @@ -1279,9 +1242,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_368x304, }, { @@ -1293,9 +1253,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, .regs = ov5693_192x160, }, { @@ -1307,9 +1264,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 0, .regs = ov5693_1296x736, }, { @@ -1321,9 +1275,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 0, .regs = ov5693_1296x976, }, { @@ -1335,9 +1286,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1636p_30fps, }, { @@ -1349,9 +1297,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_1940x1096, }, { @@ -1363,9 +1308,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1456_30fps, }, { @@ -1377,9 +1319,6 @@ struct ov5693_resolution ov5693_res_video[] = { .used = 0, .pixels_per_line = 2688, .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, .regs = ov5693_2592x1944_30fps, }, }; diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index 3f602b5aaff9..63b1bcd35399 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -586,20 +586,6 @@ struct atomisp_shading_table { __u16 *data[ATOMISP_NUM_SC_COLORS]; }; -struct atomisp_makernote_info { - /* bits 31-16: numerator, bits 15-0: denominator */ - unsigned int focal_length; - /* bits 31-16: numerator, bits 15-0: denominator*/ - unsigned int f_number_curr; - /* - * bits 31-24: max f-number numerator - * bits 23-16: max f-number denominator - * bits 15-8: min f-number numerator - * bits 7-0: min f-number denominator - */ - unsigned int f_number_range; -}; - /* parameter for MACC */ #define ATOMISP_NUM_MACC_AXES 16 struct atomisp_macc_table { @@ -650,28 +636,6 @@ struct atomisp_overlay { unsigned int overlay_start_y; }; -/* Sensor resolution specific data for AE calculation.*/ -struct atomisp_sensor_mode_data { - unsigned int coarse_integration_time_min; - unsigned int coarse_integration_time_max_margin; - unsigned int fine_integration_time_min; - unsigned int fine_integration_time_max_margin; - unsigned int fine_integration_time_def; - unsigned int frame_length_lines; - unsigned int line_length_pck; - unsigned int read_mode; - unsigned int vt_pix_clk_freq_mhz; - unsigned int crop_horizontal_start; /* Sensor crop start cord. (x0,y0)*/ - unsigned int crop_vertical_start; - unsigned int crop_horizontal_end; /* Sensor crop end cord. (x1,y1)*/ - unsigned int crop_vertical_end; - unsigned int output_width; /* input size to ISP after binning/scaling */ - unsigned int output_height; - u8 binning_factor_x; /* horizontal binning factor used */ - u8 binning_factor_y; /* vertical binning factor used */ - u16 hts; -}; - struct atomisp_exposure { unsigned int integration_time[8]; unsigned int shutter_speed[8]; @@ -914,8 +878,6 @@ struct atomisp_sensor_ae_bracketing_lut { _IOR('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table) #define ATOMISP_IOC_S_ISP_GDC_TAB \ _IOW('v', BASE_VIDIOC_PRIVATE + 10, struct atomisp_morph_table) -#define ATOMISP_IOC_ISP_MAKERNOTE \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 11, struct atomisp_makernote_info) /* macc parameter control*/ #define ATOMISP_IOC_G_ISP_MACC \ @@ -961,10 +923,6 @@ struct atomisp_sensor_ae_bracketing_lut { #define ATOMISP_IOC_CAMERA_BRIDGE \ _IOWR('v', BASE_VIDIOC_PRIVATE + 19, struct atomisp_bc_video_package) -/* Sensor resolution specific info for AE */ -#define ATOMISP_IOC_G_SENSOR_MODE_DATA \ - _IOR('v', BASE_VIDIOC_PRIVATE + 20, struct atomisp_sensor_mode_data) - #define ATOMISP_IOC_S_EXPOSURE \ _IOW('v', BASE_VIDIOC_PRIVATE + 21, struct atomisp_exposure) @@ -1093,10 +1051,6 @@ struct atomisp_sensor_ae_bracketing_lut { * Exposure, Flash and privacy (indicator) light controls, to be upstreamed */ #define V4L2_CID_CAMERA_LASTP1 (V4L2_CID_CAMERA_CLASS_BASE + 1024) -#define V4L2_CID_FOCAL_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 0) -#define V4L2_CID_FNUMBER_ABSOLUTE (V4L2_CID_CAMERA_LASTP1 + 1) -#define V4L2_CID_FNUMBER_RANGE (V4L2_CID_CAMERA_LASTP1 + 2) - /* Flash related CIDs, see also: * http://linuxtv.org/downloads/v4l-dvb-apis/extended-controls.html\ * #flash-controls */ @@ -1117,10 +1071,6 @@ struct atomisp_sensor_ae_bracketing_lut { /* Query Focus Status */ #define V4L2_CID_FOCUS_STATUS (V4L2_CID_CAMERA_LASTP1 + 14) -/* Query sensor's binning factor */ -#define V4L2_CID_BIN_FACTOR_HORZ (V4L2_CID_CAMERA_LASTP1 + 15) -#define V4L2_CID_BIN_FACTOR_VERT (V4L2_CID_CAMERA_LASTP1 + 16) - /* number of frames to skip at stream start */ #define V4L2_CID_G_SKIP_FRAMES (V4L2_CID_CAMERA_LASTP1 + 17) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h index 5463d11d4295..64bd54835c32 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h @@ -21,8 +21,6 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, struct camera_sensor_platform_data *plat_data, enum intel_v4l2_subdev_type type); -struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter, - struct i2c_board_info *board_info); int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd); int gmin_get_var_int(struct device *dev, bool is_gmin, const char *var, int def); diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 0253661d4332..539b21d39d3b 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -125,13 +125,7 @@ struct intel_v4l2_subdev_id { enum atomisp_camera_port port; }; -struct intel_v4l2_subdev_i2c_board_info { - struct i2c_board_info board_info; - int i2c_adapter_id; -}; - struct intel_v4l2_subdev_table { - struct intel_v4l2_subdev_i2c_board_info v4l2_subdev; enum intel_v4l2_subdev_type type; enum atomisp_camera_port port; struct v4l2_subdev *subdev; @@ -210,7 +204,6 @@ struct camera_mipi_info { unsigned int num_lanes; enum atomisp_input_format input_format; enum atomisp_bayer_order raw_bayer_order; - struct atomisp_sensor_mode_data data; enum atomisp_input_format metadata_format; u32 metadata_width; u32 metadata_height; @@ -218,6 +211,10 @@ struct camera_mipi_info { }; const struct atomisp_platform_data *atomisp_get_platform_data(void); +int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes, + enum atomisp_input_format format, + enum atomisp_bayer_order bayer_order); +void atomisp_unregister_subdev(struct v4l2_subdev *subdev); /* API from old platform_camera.h, new CPUID implementation */ #define __IS_SOC(x) (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && \ diff --git a/drivers/staging/media/atomisp/notes.txt b/drivers/staging/media/atomisp/notes.txt index d3cf6ed547ae..c04c283ff438 100644 --- a/drivers/staging/media/atomisp/notes.txt +++ b/drivers/staging/media/atomisp/notes.txt @@ -36,12 +36,6 @@ a camera_mipi_info struct. This struct is allocated/managed by the core atomisp code. The most important parts of the struct are filled by the atomisp core itself, like e.g. the port number. -The sensor drivers on a set_fmt call do fill in camera_mipi_info.data -which is a atomisp_sensor_mode_data struct. This gets filled from -a function called <sensor_name>_get_intg_factor(). This struct is not -used by the atomisp code at all. It is returned to userspace by -a ATOMISP_IOC_G_SENSOR_MODE_DATA and the Android userspace does use this. - Other members of camera_mipi_info which are set by some drivers are: -metadata_width, metadata_height, metadata_effective_width, set by the ov5693 driver (and used by the atomisp core) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index d8c7e7367386..47f18ac5e40e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -280,14 +280,14 @@ int atomisp_freq_scaling(struct atomisp_device *isp, done: dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq); - if ((new_freq == isp->sw_contex.running_freq) && !force) + if ((new_freq == isp->running_freq) && !force) return 0; dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq); ret = write_target_freq_to_hw(isp, new_freq); if (!ret) { - isp->sw_contex.running_freq = new_freq; + isp->running_freq = new_freq; trace_ipu_pstate(new_freq, -1); } return ret; @@ -679,7 +679,8 @@ void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state vb2_buffer_done(&frame->vb.vb2_buf, state); } -void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames) +void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state, + bool warn_on_css_frames) { struct ia_css_frame *frame, *_frame; unsigned long irqflags; @@ -689,15 +690,15 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_ list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) { if (warn_on_css_frames) dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n"); - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); } list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue) - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) { pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0; - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); } spin_unlock_irqrestore(&pipe->irq_lock, irqflags); @@ -706,10 +707,10 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_ /* Returns queued buffers back to video-core */ void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd) { - atomisp_flush_video_pipe(&asd->video_out_capture, false); - atomisp_flush_video_pipe(&asd->video_out_vf, false); - atomisp_flush_video_pipe(&asd->video_out_preview, false); - atomisp_flush_video_pipe(&asd->video_out_video_capture, false); + atomisp_flush_video_pipe(&asd->video_out_capture, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_vf, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_preview, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_video_capture, VB2_BUF_STATE_ERROR, false); } /* clean out the parameters that did not apply */ @@ -4211,25 +4212,6 @@ int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag, return 0; } -/* - * Function to get sensor specific info for current resolution, - * which will be used for auto exposure conversion. - */ -int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, - struct atomisp_sensor_mode_data *config) -{ - struct camera_mipi_info *mipi_info; - struct atomisp_device *isp = asd->isp; - - mipi_info = atomisp_to_sensor_mipi_info( - isp->inputs[asd->input_curr].camera); - if (!mipi_info) - return -EINVAL; - - memcpy(config, &mipi_info->data, sizeof(*config)); - return 0; -} - static void __atomisp_update_stream_env(struct atomisp_sub_device *asd, u16 stream_index, struct atomisp_input_stream_info *stream_info) { @@ -5010,7 +4992,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) struct v4l2_subdev_format vformat = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - struct v4l2_mbus_framefmt *ffmt = &vformat.format; struct v4l2_rect isp_sink_crop; u16 source_pad = atomisp_subdev_source_pad(vdev); struct v4l2_subdev_fh fh; @@ -5049,17 +5030,17 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) /* Ensure that the resolution is equal or below the maximum supported */ vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE; - v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format_bridge->mbus_code); - ffmt->height += padding_h; - ffmt->width += padding_w; + v4l2_fill_mbus_format(&vformat.format, &f->fmt.pix, format_bridge->mbus_code); + vformat.format.height += padding_h; + vformat.format.width += padding_w; ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad, set_fmt, NULL, &vformat); if (ret) return ret; - f->fmt.pix.width = ffmt->width - padding_w; - f->fmt.pix.height = ffmt->height - padding_h; + f->fmt.pix.width = vformat.format.width - padding_w; + f->fmt.pix.height = vformat.format.height - padding_h; snr_fmt = f->fmt.pix; backup_fmt = snr_fmt; @@ -5182,9 +5163,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) if (!atomisp_subdev_format_conversion(asd, source_pad)) { padding_w = 0; padding_h = 0; - } else if (IS_BYT) { - padding_w = 12; - padding_h = 12; } /* construct resolution supported by isp */ @@ -5492,42 +5470,6 @@ out: return ret; } -int atomisp_exif_makernote(struct atomisp_sub_device *asd, - struct atomisp_makernote_info *config) -{ - struct v4l2_control ctrl; - struct atomisp_device *isp = asd->isp; - - ctrl.id = V4L2_CID_FOCAL_ABSOLUTE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for focal length\n"); - return -EINVAL; - } else { - config->focal_length = ctrl.value; - } - - ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for f-number\n"); - return -EINVAL; - } else { - config->f_number_curr = ctrl.value; - } - - ctrl.id = V4L2_CID_FNUMBER_RANGE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for f number range\n"); - return -EINVAL; - } else { - config->f_number_range = ctrl.value; - } - - return 0; -} - int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, struct atomisp_cont_capture_conf *cvf_config) { diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index b8911491581a..733b9f8cd06f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -57,7 +57,8 @@ struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev); int atomisp_reset(struct atomisp_device *isp); int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe); void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state); -void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames); +void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state, + bool warn_on_css_frames); void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd); void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd); @@ -258,9 +259,6 @@ int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd, int atomisp_compare_grid(struct atomisp_sub_device *asd, struct atomisp_grid_info *atomgrid); -int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, - struct atomisp_sensor_mode_data *config); - /* This function looks up the closest available resolution. */ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, bool *res_overflow); @@ -273,9 +271,6 @@ int atomisp_set_shading_table(struct atomisp_sub_device *asd, int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, struct atomisp_cont_capture_conf *cvf_config); -int atomisp_exif_makernote(struct atomisp_sub_device *asd, - struct atomisp_makernote_info *config); - void atomisp_free_internal_buffers(struct atomisp_sub_device *asd); int atomisp_s_ae_window(struct atomisp_sub_device *asd, diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 4a9268bac8a9..b00bc0b7aaad 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -175,47 +175,8 @@ static const struct v4l2_subdev_ops csi2_ops = { .pad = &csi2_pad_ops, }; -/* - * csi2_link_setup - Setup CSI2 connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL or zero on success - */ -static int csi2_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); - u32 result = local->index | is_media_entity_v4l2_subdev(remote->entity); - - switch (result) { - case CSI2_PAD_SOURCE | MEDIA_ENT_F_OLD_BASE: - /* not supported yet */ - return -EINVAL; - - case CSI2_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: - if (flags & MEDIA_LNK_FL_ENABLED) { - if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV) - return -EBUSY; - csi2->output |= CSI2_OUTPUT_ISP_SUBDEV; - } else { - csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV; - } - break; - - default: - /* Link from camera to CSI2 is fixed... */ - return -EINVAL; - } - return 0; -} - /* media operations */ static const struct media_entity_operations csi2_media_ops = { - .link_setup = csi2_link_setup, .link_validate = v4l2_subdev_link_validate, }; @@ -242,7 +203,7 @@ static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2, pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; me->ops = &csi2_media_ops; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_VID_IF_BRIDGE; ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads); if (ret < 0) return ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h index e35711be8a37..b245b2f5ce99 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h @@ -25,9 +25,6 @@ #define CSI2_PAD_SOURCE 1 #define CSI2_PADS_NUM 2 -#define CSI2_OUTPUT_ISP_SUBDEV BIT(0) -#define CSI2_OUTPUT_MEMORY BIT(1) - struct atomisp_device; struct v4l2_device; struct atomisp_sub_device; @@ -39,8 +36,6 @@ struct atomisp_mipi_csi2_device { struct v4l2_ctrl_handler ctrls; struct atomisp_device *isp; - - u32 output; /* output direction */ }; int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index acea7492847d..ce01479bdd68 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -80,7 +80,7 @@ static int atomisp_queue_setup(struct vb2_queue *vq, out: mutex_unlock(&pipe->asd->isp->mutex); - return 0; + return ret; } static int atomisp_buf_init(struct vb2_buffer *vb) @@ -624,7 +624,7 @@ static void atomisp_buf_cleanup(struct vb2_buffer *vb) hmm_free(frame->data); } -static const struct vb2_ops atomisp_vb2_ops = { +const struct vb2_ops atomisp_vb2_ops = { .queue_setup = atomisp_queue_setup, .buf_init = atomisp_buf_init, .buf_cleanup = atomisp_buf_cleanup, @@ -633,40 +633,6 @@ static const struct vb2_ops atomisp_vb2_ops = { .stop_streaming = atomisp_stop_streaming, }; -static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) -{ - int ret; - - /* init locks */ - spin_lock_init(&pipe->irq_lock); - mutex_init(&pipe->vb_queue_mutex); - - /* Init videobuf2 queue structure */ - pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; - pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); - pipe->vb_queue.ops = &atomisp_vb2_ops; - pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; - pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - ret = vb2_queue_init(&pipe->vb_queue); - if (ret) - return ret; - - pipe->vdev.queue = &pipe->vb_queue; - pipe->vdev.queue->lock = &pipe->vb_queue_mutex; - - INIT_LIST_HEAD(&pipe->activeq); - INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); - INIT_LIST_HEAD(&pipe->per_frame_params); - memset(pipe->frame_request_config_id, 0, - VIDEO_MAX_FRAME * sizeof(unsigned int)); - memset(pipe->frame_params, 0, - VIDEO_MAX_FRAME * - sizeof(struct atomisp_css_params_with_list *)); - - return 0; -} - static void atomisp_dev_init_struct(struct atomisp_device *isp) { unsigned int i; @@ -681,7 +647,7 @@ static void atomisp_dev_init_struct(struct atomisp_device *isp) * For Merrifield, frequency is scalable. * After boot-up, the default frequency is 200MHz. */ - isp->sw_contex.running_freq = ISP_FREQ_200MHZ; + isp->running_freq = ISP_FREQ_200MHZ; } static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd) @@ -757,25 +723,6 @@ static int atomisp_open(struct file *file) mutex_lock(&isp->mutex); asd->subdev.devnode = vdev; - /* Deferred firmware loading case. */ - if (isp->css_env.isp_css_fw.bytes == 0) { - dev_err(isp->dev, "Deferred firmware load.\n"); - isp->firmware = atomisp_load_firmware(isp); - if (!isp->firmware) { - dev_err(isp->dev, "Failed to load ISP firmware.\n"); - ret = -ENOENT; - goto error; - } - ret = atomisp_css_load_firmware(isp); - if (ret) { - dev_err(isp->dev, "Failed to init css.\n"); - goto error; - } - /* No need to keep FW in memory anymore. */ - release_firmware(isp->firmware); - isp->firmware = NULL; - isp->css_env.isp_css_fw.data = NULL; - } if (!isp->input_cnt) { dev_err(isp->dev, "no camera attached\n"); @@ -792,10 +739,6 @@ static int atomisp_open(struct file *file) return -EBUSY; } - ret = atomisp_init_pipe(pipe); - if (ret) - goto error; - if (atomisp_dev_users(isp)) { dev_dbg(isp->dev, "skip init isp in open\n"); goto init_subdev; @@ -821,13 +764,13 @@ init_subdev: goto done; atomisp_subdev_init_struct(asd); + /* Ensure that a mode is set */ + v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); done: pipe->users++; mutex_unlock(&isp->mutex); - /* Ensure that a mode is set */ - v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); return 0; @@ -885,13 +828,17 @@ static int atomisp_release(struct file *file) atomisp_css_free_stat_buffers(asd); atomisp_free_internal_buffers(asd); - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - core, s_power, 0); - if (ret) - dev_warn(isp->dev, "Failed to power-off sensor\n"); - /* clear the asd field to show this camera is not used */ - isp->inputs[asd->input_curr].asd = NULL; + if (isp->inputs[asd->input_curr].asd == asd) { + ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, + core, s_power, 0); + if (ret && ret != -ENOIOCTLCMD) + dev_warn(isp->dev, "Failed to power-off sensor\n"); + + /* clear the asd field to show this camera is not used */ + isp->inputs[asd->input_curr].asd = NULL; + } + spin_lock_irqsave(&isp->lock, flags); asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; spin_unlock_irqrestore(&isp->lock, flags); @@ -901,12 +848,6 @@ static int atomisp_release(struct file *file) atomisp_destroy_pipes_stream_force(asd); - if (defer_fw_load) { - ia_css_unload_firmware(); - isp->css_env.isp_css_fw.data = NULL; - isp->css_env.isp_css_fw.bytes = 0; - } - ret = v4l2_subdev_call(isp->flash, core, s_power, 0); if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off flash\n"); diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h index 10e43126b693..883c1851c1c9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.h +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h @@ -31,8 +31,7 @@ unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd); int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd); +extern const struct vb2_ops atomisp_vb2_ops; extern const struct v4l2_file_operations atomisp_fops; -extern bool defer_fw_load; - #endif /* __ATOMISP_FOPS_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 3d41fab661cf..7fc7dfa56172 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -57,8 +57,12 @@ enum clock_rate { #define LDO_1P8V_OFF 0x58 /* ... bottom bit is "enabled" */ /* CRYSTAL COVE PMIC register set */ -#define CRYSTAL_1P8V_REG 0x57 -#define CRYSTAL_2P8V_REG 0x5d +#define CRYSTAL_BYT_1P8V_REG 0x5d +#define CRYSTAL_BYT_2P8V_REG 0x66 + +#define CRYSTAL_CHT_1P8V_REG 0x57 +#define CRYSTAL_CHT_2P8V_REG 0x5d + #define CRYSTAL_ON 0x63 #define CRYSTAL_OFF 0x62 @@ -145,7 +149,6 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, enum intel_v4l2_subdev_type type) { int i; - struct i2c_board_info *bi; struct gmin_subdev *gs; struct i2c_client *client = v4l2_get_subdevdata(subdev); struct acpi_device *adev = ACPI_COMPANION(&client->dev); @@ -158,6 +161,14 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, * tickled during suspend/resume. This has caused power and * performance issues on multiple devices. */ + + /* + * Turn off the device before disabling ACPI power resources + * (the sensor driver has already probed it at this point). + * This avoids leaking the reference count of the (possibly shared) + * ACPI power resources which were enabled/referenced before probe(). + */ + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->power.flags.power_resources = 0; for (i = 0; i < MAX_SUBDEVS; i++) @@ -179,36 +190,10 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, pdata.subdevs[i].type = type; pdata.subdevs[i].port = gs->csi_port; pdata.subdevs[i].subdev = subdev; - pdata.subdevs[i].v4l2_subdev.i2c_adapter_id = client->adapter->nr; - - /* Convert i2c_client to i2c_board_info */ - bi = &pdata.subdevs[i].v4l2_subdev.board_info; - memcpy(bi->type, client->name, I2C_NAME_SIZE); - bi->flags = client->flags; - bi->addr = client->addr; - bi->irq = client->irq; - bi->platform_data = plat_data; - return 0; } EXPORT_SYMBOL_GPL(atomisp_register_i2c_module); -struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter, - struct i2c_board_info *board_info) -{ - int i; - - for (i = 0; i < MAX_SUBDEVS && pdata.subdevs[i].type; i++) { - struct intel_v4l2_subdev_table *sd = &pdata.subdevs[i]; - - if (sd->v4l2_subdev.i2c_adapter_id == adapter->nr && - sd->v4l2_subdev.board_info.addr == board_info->addr) - return sd->subdev; - } - return NULL; -} -EXPORT_SYMBOL_GPL(atomisp_gmin_find_subdev); - int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd) { int i, j; @@ -843,6 +828,7 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) struct gmin_subdev *gs = find_gmin_subdev(subdev); int ret; int value; + int reg; if (!gs || gs->v1p8_on == on) return 0; @@ -898,10 +884,15 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) LDO10_REG, value, 0xff); break; case PMIC_CRYSTALCOVE: + if (IS_ISP2401) + reg = CRYSTAL_CHT_1P8V_REG; + else + reg = CRYSTAL_BYT_1P8V_REG; + value = on ? CRYSTAL_ON : CRYSTAL_OFF; ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_1P8V_REG, value, 0xff); + reg, value, 0xff); break; default: dev_err(subdev->dev, "Couldn't set power mode for v1p8\n"); @@ -918,6 +909,7 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) struct gmin_subdev *gs = find_gmin_subdev(subdev); int ret; int value; + int reg; if (WARN_ON(!gs)) return -ENODEV; @@ -974,10 +966,15 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) LDO9_REG, value, 0xff); break; case PMIC_CRYSTALCOVE: + if (IS_ISP2401) + reg = CRYSTAL_CHT_2P8V_REG; + else + reg = CRYSTAL_BYT_2P8V_REG; + value = on ? CRYSTAL_ON : CRYSTAL_OFF; ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_2P8V_REG, value, 0xff); + reg, value, 0xff); break; default: dev_err(subdev->dev, "Couldn't set power mode for v2p8\n"); @@ -1095,6 +1092,67 @@ static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag) return 0; } +int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes, + enum atomisp_input_format format, + enum atomisp_bayer_order bayer_order) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct acpi_device *adev = ACPI_COMPANION(&client->dev); + int i, ret, clock_num, port = 0; + + if (adev) { + /* Get ACPI _PR0 derived clock to determine the csi_port default */ + if (acpi_device_power_manageable(adev)) { + clock_num = atomisp_get_acpi_power(&client->dev); + + /* Compare clock to CsiPort 1 pmc-clock used in the CHT/BYT reference designs */ + if (IS_ISP2401) + port = clock_num == 4 ? 1 : 0; + else + port = clock_num == 0 ? 1 : 0; + } + + port = gmin_get_var_int(&client->dev, false, "CsiPort", port); + lanes = gmin_get_var_int(&client->dev, false, "CsiLanes", lanes); + } + + for (i = 0; i < MAX_SUBDEVS; i++) + if (!pdata.subdevs[i].type) + break; + + if (i >= MAX_SUBDEVS) { + dev_err(&client->dev, "Error too many subdevs already registered\n"); + return -ENOMEM; + } + + ret = camera_sensor_csi_alloc(subdev, port, lanes, format, bayer_order); + if (ret) + return ret; + + pdata.subdevs[i].type = RAW_CAMERA; + pdata.subdevs[i].port = port; + pdata.subdevs[i].subdev = subdev; + return 0; +} +EXPORT_SYMBOL_GPL(atomisp_register_sensor_no_gmin); + +void atomisp_unregister_subdev(struct v4l2_subdev *subdev) +{ + int i; + + for (i = 0; i < MAX_SUBDEVS; i++) { + if (pdata.subdevs[i].subdev != subdev) + continue; + + camera_sensor_csi_free(subdev); + pdata.subdevs[i].subdev = NULL; + pdata.subdevs[i].type = 0; + pdata.subdevs[i].port = 0; + break; + } +} +EXPORT_SYMBOL_GPL(atomisp_unregister_subdev); + static struct camera_vcm_control *gmin_get_vcm_ctrl(struct v4l2_subdev *subdev, char *camera_module) { diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h index 653e6d74a966..fa38d91420cf 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h @@ -194,10 +194,6 @@ struct atomisp_regs { u32 csi_access_viol; }; -struct atomisp_sw_contex { - int running_freq; -}; - #define ATOMISP_DEVICE_STREAMING_DISABLED 0 #define ATOMISP_DEVICE_STREAMING_ENABLED 1 #define ATOMISP_DEVICE_STREAMING_STOPPING 2 @@ -214,6 +210,7 @@ struct atomisp_device { void __iomem *base; const struct firmware *firmware; + struct dev_pm_domain pm_domain; struct pm_qos_request pm_qos; s32 max_isr_latency; @@ -242,7 +239,6 @@ struct atomisp_device { struct v4l2_subdev *motor; struct atomisp_regs saved_regs; - struct atomisp_sw_contex sw_contex; struct atomisp_css_env css_env; /* isp timeout status flag */ @@ -257,6 +253,7 @@ struct atomisp_device { unsigned int mipi_frame_size; const struct atomisp_dfs_config *dfs; unsigned int hpll_freq; + unsigned int running_freq; bool css_initialized; }; diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index cb01ba65c88f..d1314bdbf7d5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -173,24 +173,6 @@ static struct v4l2_queryctrl ci_v4l2_controls[] = { .default_value = 1, }, { - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Horizontal binning factor", - .minimum = 0, - .maximum = 10, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical binning factor", - .minimum = 0, - .maximum = 10, - .step = 1, - .default_value = 0, - }, - { .id = V4L2_CID_2A_STATUS, .type = V4L2_CTRL_TYPE_BITMASK, .name = "AE and AWB status", @@ -636,10 +618,10 @@ static int atomisp_enum_input(struct file *file, void *fh, static unsigned int atomisp_subdev_streaming_count(struct atomisp_sub_device *asd) { - return asd->video_out_preview.vb_queue.start_streaming_called - + asd->video_out_capture.vb_queue.start_streaming_called - + asd->video_out_video_capture.vb_queue.start_streaming_called - + asd->video_out_vf.vb_queue.start_streaming_called; + return vb2_start_streaming_called(&asd->video_out_preview.vb_queue) + + vb2_start_streaming_called(&asd->video_out_capture.vb_queue) + + vb2_start_streaming_called(&asd->video_out_video_capture.vb_queue) + + vb2_start_streaming_called(&asd->video_out_vf.vb_queue); } unsigned int atomisp_streaming_count(struct atomisp_device *isp) @@ -718,7 +700,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) asd->input_curr != input) { ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, core, s_power, 0); - if (ret) + if (ret && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off sensor\n"); /* clear the asd field to show this camera is not used */ @@ -727,7 +709,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) /* powe on the new sensor */ ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, 1); - if (ret) { + if (ret && ret != -ENOIOCTLCMD) { dev_err(isp->dev, "Failed to power-on sensor\n"); return ret; } @@ -1067,13 +1049,23 @@ error: return -ENOMEM; } +/* + * FIXME the abuse of buf->reserved2 in the qbuf and dqbuf wrappers comes from + * the original atomisp buffer handling and should be replaced with proper V4L2 + * per frame parameters use. + * + * Once this is fixed these wrappers can be removed, replacing them with direct + * calls to vb2_ioctl_[d]qbuf(). + */ static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - /* FIXME this abuse of buf->reserved2 comes from the original atomisp buffer handling */ + if (buf->index >= vdev->queue->num_buffers) + return -EINVAL; + if (!atomisp_is_vf_pipe(pipe) && (buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) { /* this buffer will have a per-frame parameter */ @@ -1106,7 +1098,6 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer vb = pipe->vb_queue.bufs[buf->index]; frame = vb_to_frame(vb); - /* FIXME this abuse of buf->reserved* comes from the original atomisp buffer handling */ buf->reserved = asd->frame_status[buf->index]; /* @@ -1354,7 +1345,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) ret = atomisp_css_start(asd, css_pipe_id, false); if (ret) { - atomisp_flush_video_pipe(pipe, true); + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); goto out_unlock; } @@ -1530,7 +1521,7 @@ void atomisp_stop_streaming(struct vb2_queue *vq) css_pipe_id = atomisp_get_css_pipe_id(asd); atomisp_css_stop(asd, css_pipe_id, false); - atomisp_flush_video_pipe(pipe, true); + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_ERROR, true); atomisp_subdev_cleanup_pending_events(asd); stopsensor: @@ -1631,7 +1622,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh, switch (control->id) { case V4L2_CID_IRIS_ABSOLUTE: case V4L2_CID_EXPOSURE_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: case V4L2_CID_2A_STATUS: case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: case V4L2_CID_EXPOSURE: @@ -1828,9 +1818,6 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh, case V4L2_CID_EXPOSURE_ABSOLUTE: case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_IRIS_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: - case V4L2_CID_BIN_FACTOR_HORZ: - case V4L2_CID_BIN_FACTOR_VERT: case V4L2_CID_3A_LOCK: case V4L2_CID_TEST_PATTERN: case V4L2_CID_TEST_PATTERN_COLOR_R: @@ -1940,7 +1927,6 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh, case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_EXPOSURE_METERING: case V4L2_CID_IRIS_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: case V4L2_CID_VCM_TIMING: case V4L2_CID_VCM_SLEW: case V4L2_CID_3A_LOCK: @@ -2276,14 +2262,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, err = atomisp_fixed_pattern_table(asd, arg); break; - case ATOMISP_IOC_ISP_MAKERNOTE: - err = atomisp_exif_makernote(asd, arg); - break; - - case ATOMISP_IOC_G_SENSOR_MODE_DATA: - err = atomisp_get_sensor_mode_data(asd, arg); - break; - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA: if (motor) err = v4l2_subdev_call(motor, core, ioctl, cmd, arg); diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index cadc468b4c2f..9cfb85c61db6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -25,9 +25,11 @@ #include <media/v4l2-event.h> #include <media/v4l2-mediabus.h> +#include <media/videobuf2-vmalloc.h> #include "atomisp_cmd.h" #include "atomisp_common.h" #include "atomisp_compat.h" +#include "atomisp_fops.h" #include "atomisp_internal.h" const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = { @@ -574,40 +576,6 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd, sel->target, sel->flags, &sel->r); } -static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd) -{ - struct v4l2_control ctrl = {0}; - struct atomisp_device *isp = asd->isp; - int hbin, vbin; - int ret; - - if (isp->inputs[asd->input_curr].type == FILE_INPUT || - isp->inputs[asd->input_curr].type == TEST_PATTERN) - return 0; - - ctrl.id = V4L2_CID_BIN_FACTOR_HORZ; - ret = - v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler, - &ctrl); - hbin = ctrl.value; - ctrl.id = V4L2_CID_BIN_FACTOR_VERT; - ret |= - v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler, - &ctrl); - vbin = ctrl.value; - - /* - * ISP needs to know binning factor from sensor. - * In case horizontal and vertical sensor's binning factors - * are different or sensor does not support binning factor CID, - * ISP will apply default 0 value. - */ - if (ret || hbin != vbin) - hbin = 0; - - return hbin; -} - void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, uint32_t which, @@ -645,7 +613,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, ATOMISP_INPUT_STREAM_GENERAL, ffmt); atomisp_css_input_set_binning_factor(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, - atomisp_get_sensor_bin_factor(isp_sd)); + 0); atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, fc->bayer_order); atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, @@ -746,85 +714,8 @@ static void isp_subdev_init_params(struct atomisp_sub_device *asd) } } -/* -* isp_subdev_link_setup - Setup isp subdev connections -* @entity: ispsubdev media entity -* @local: Pad at the local end of the link -* @remote: Pad at the remote end of the link -* @flags: Link flags -* -* return -EINVAL or zero on success -*/ -static int isp_subdev_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); - struct atomisp_device *isp = isp_sd->isp; - unsigned int i; - - switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) { - case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: - /* Read from the sensor CSI2-ports. */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; - break; - } - - if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE) - return -EBUSY; - - for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) { - if (remote->entity != &isp->csi2_port[i].subdev.entity) - continue; - - isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i; - return 0; - } - - return -EINVAL; - - case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE: - /* read from memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 && - isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1 - + ATOMISP_CAMERA_NR_PORTS)) - return -EBUSY; - isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY; - } else { - if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY) - isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; - } - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - default: - return -EINVAL; - } - - return 0; -} - /* media operations */ static const struct media_entity_operations isp_subdev_media_ops = { - .link_setup = isp_subdev_link_setup, .link_validate = v4l2_subdev_link_validate, /* .set_power = v4l2_subdev_set_power, */ }; @@ -1057,23 +948,37 @@ static const struct v4l2_ctrl_config ctrl_depth_mode = { .def = 0, }; -static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, - struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) +static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, + struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) { + int ret; + pipe->type = buf_type; pipe->asd = asd; pipe->isp = asd->isp; spin_lock_init(&pipe->irq_lock); mutex_init(&pipe->vb_queue_mutex); + + /* Init videobuf2 queue structure */ + pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; + pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); + pipe->vb_queue.ops = &atomisp_vb2_ops; + pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; + pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&pipe->vb_queue); + if (ret) + return ret; + + pipe->vdev.queue = &pipe->vb_queue; + pipe->vdev.queue->lock = &pipe->vb_queue_mutex; + INIT_LIST_HEAD(&pipe->buffers_in_css); INIT_LIST_HEAD(&pipe->activeq); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); INIT_LIST_HEAD(&pipe->per_frame_params); - memset(pipe->frame_request_config_id, - 0, VIDEO_MAX_FRAME * sizeof(unsigned int)); - memset(pipe->frame_params, - 0, VIDEO_MAX_FRAME * - sizeof(struct atomisp_css_params_with_list *)); + + return 0; } /* @@ -1089,8 +994,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) struct media_entity *me = &sd->entity; int ret; - asd->input = ATOMISP_SUBDEV_INPUT_NONE; - v4l2_subdev_init(sd, &isp_subdev_v4l2_ops); sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index); v4l2_set_subdevdata(sd, asd); @@ -1114,22 +1017,30 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) MEDIA_BUS_FMT_SBGGR10_1X10; me->ops = &isp_subdev_media_ops; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads); if (ret < 0) return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_preview, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_vf, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_capture, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE", ATOMISP_RUN_MODE_STILL_CAPTURE); diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index bd2872cbb50c..daa6077a83bd 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -30,18 +30,6 @@ /* EXP_ID's ranger is 1 ~ 250 */ #define ATOMISP_MAX_EXP_ID (250) -enum atomisp_subdev_input_entity { - ATOMISP_SUBDEV_INPUT_NONE, - ATOMISP_SUBDEV_INPUT_MEMORY, - ATOMISP_SUBDEV_INPUT_CSI2, - /* - * The following enum for CSI2 port must go together in one row. - * Otherwise it breaks the code logic. - */ - ATOMISP_SUBDEV_INPUT_CSI2_PORT1, - ATOMISP_SUBDEV_INPUT_CSI2_PORT2, - ATOMISP_SUBDEV_INPUT_CSI2_PORT3, -}; #define ATOMISP_SUBDEV_PAD_SINK 0 /* capture output for still frames */ @@ -267,7 +255,6 @@ struct atomisp_sub_device { struct atomisp_pad_format fmt[ATOMISP_SUBDEV_PADS_NUM]; u16 capture_pad; /* main capture pad; defines much of isp config */ - enum atomisp_subdev_input_entity input; unsigned int output; struct atomisp_video_pipe video_out_capture; /* capture output */ struct atomisp_video_pipe video_out_vf; /* viewfinder output */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c index e29a96da5f98..074826a5b706 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c @@ -152,7 +152,7 @@ int atomisp_tpg_init(struct atomisp_device *isp) v4l2_set_subdevdata(sd, tpg); pads[0].flags = MEDIA_PAD_FL_SINK; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; ret = media_entity_pads_init(me, 1, pads); if (ret < 0) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index e786b81921da..ba628f7cf385 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -19,6 +19,7 @@ */ #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <linux/pm_qos.h> #include <linux/timer.h> @@ -57,12 +58,6 @@ static uint skip_fwload; module_param(skip_fwload, uint, 0644); MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load"); -/* memory optimization: deferred firmware loading */ -bool defer_fw_load; -module_param(defer_fw_load, bool, 0644); -MODULE_PARM_DESC(defer_fw_load, - "Defer FW loading until device is opened (default:disable)"); - /* cross componnet debug message flag */ int dbg_level; module_param(dbg_level, int, 0644); @@ -524,7 +519,7 @@ static int atomisp_save_iunit_reg(struct atomisp_device *isp) return 0; } -static int __maybe_unused atomisp_restore_iunit_reg(struct atomisp_device *isp) +static int atomisp_restore_iunit_reg(struct atomisp_device *isp) { struct pci_dev *pdev = to_pci_dev(isp->dev); @@ -637,31 +632,21 @@ done: */ static void punit_ddr_dvfs_enable(bool enable) { - int door_bell = 1 << 8; - int max_wait = 30; int reg; iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); if (enable) { reg &= ~(MRFLD_BIT0 | MRFLD_BIT1); } else { - reg |= (MRFLD_BIT1 | door_bell); + reg |= MRFLD_BIT1; reg &= ~(MRFLD_BIT0); } iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSDVFS, reg); - - /* Check Req_ACK to see freq status, wait until door_bell is cleared */ - while ((reg & door_bell) && max_wait--) { - iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); - usleep_range(100, 500); - } - - if (max_wait == -1) - pr_info("DDR DVFS, door bell is not cleared within 3ms\n"); } static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) { + struct pci_dev *pdev = to_pci_dev(isp->dev); unsigned long timeout; u32 val = enable ? MRFLD_ISPSSPM0_IUNIT_POWER_ON : MRFLD_ISPSSPM0_IUNIT_POWER_OFF; @@ -669,16 +654,10 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) dev_dbg(isp->dev, "IUNIT power-%s.\n", enable ? "on" : "off"); /* WA for P-Unit, if DVFS enabled, ISP timeout observed */ - if (IS_CHT && enable) + if (IS_CHT && enable) { punit_ddr_dvfs_enable(false); - - /* - * FIXME:WA for ECS28A, with this sleep, CTS - * android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceAbort - * PASS, no impact on other platforms - */ - if (IS_BYT && enable) - msleep(10); + msleep(20); + } /* Write to ISPSSPM0 bit[1:0] to power on/off the IUNIT */ iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, @@ -703,6 +682,7 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) tmp = (tmp >> MRFLD_ISPSSPM0_ISPSSS_OFFSET) & MRFLD_ISPSSPM0_ISPSSC_MASK; if (tmp == val) { trace_ipu_cstate(enable); + pdev->current_state = enable ? PCI_D0 : PCI_D3cold; return 0; } @@ -743,6 +723,7 @@ int atomisp_power_off(struct device *dev) pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg); cpu_latency_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE); + pci_save_state(pdev); return atomisp_mrfld_power(isp, false); } @@ -756,6 +737,7 @@ int atomisp_power_on(struct device *dev) if (ret) return ret; + pci_restore_state(to_pci_dev(dev)); cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency); /*restore register values for iUnit and iUnitPHY registers*/ @@ -767,7 +749,7 @@ int atomisp_power_on(struct device *dev) return atomisp_css_init(isp); } -static int __maybe_unused atomisp_suspend(struct device *dev) +static int atomisp_suspend(struct device *dev) { struct atomisp_device *isp = (struct atomisp_device *) dev_get_drvdata(dev); @@ -790,10 +772,12 @@ static int __maybe_unused atomisp_suspend(struct device *dev) } spin_unlock_irqrestore(&isp->lock, flags); + pm_runtime_resume(dev); + return atomisp_power_off(dev); } -static int __maybe_unused atomisp_resume(struct device *dev) +static int atomisp_resume(struct device *dev) { return atomisp_power_on(dev); } @@ -953,45 +937,9 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) /* FIXME: should, instead, use I2C probe */ for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) { - struct v4l2_subdev *subdev; - struct i2c_board_info *board_info = - &subdevs->v4l2_subdev.board_info; - struct i2c_adapter *adapter = - i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id); - - dev_info(isp->dev, "Probing Subdev %s\n", board_info->type); - - if (!adapter) { - dev_err(isp->dev, - "Failed to find i2c adapter for subdev %s\n", - board_info->type); - break; - } - - /* In G-Min, the sensor devices will already be probed - * (via ACPI) and registered, do not create new - * ones */ - subdev = atomisp_gmin_find_subdev(adapter, board_info); - if (!subdev) { - dev_warn(isp->dev, "Subdev %s not found\n", - board_info->type); + ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdevs->subdev); + if (ret) continue; - } - ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdev); - if (ret) { - dev_warn(isp->dev, "Subdev %s detection fail\n", - board_info->type); - continue; - } - - if (!subdev) { - dev_warn(isp->dev, "Subdev %s detection fail\n", - board_info->type); - continue; - } - - dev_info(isp->dev, "Subdev %s successfully register\n", - board_info->type); switch (subdevs->type) { case RAW_CAMERA: @@ -1008,7 +956,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) isp->inputs[isp->input_cnt].type = subdevs->type; isp->inputs[isp->input_cnt].port = subdevs->port; - isp->inputs[isp->input_cnt].camera = subdev; + isp->inputs[isp->input_cnt].camera = subdevs->subdev; isp->inputs[isp->input_cnt].sensor_index = 0; /* * initialize the subdev frame size, then next we can @@ -1020,22 +968,18 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) break; case CAMERA_MOTOR: if (isp->motor) { - dev_warn(isp->dev, - "too many atomisp motors, ignored %s\n", - board_info->type); + dev_warn(isp->dev, "too many atomisp motors\n"); continue; } - isp->motor = subdev; + isp->motor = subdevs->subdev; break; case LED_FLASH: case XENON_FLASH: if (isp->flash) { - dev_warn(isp->dev, - "too many atomisp flash devices, ignored %s\n", - board_info->type); + dev_warn(isp->dev, "too many atomisp flash devices\n"); continue; } - isp->flash = subdev; + isp->flash = subdevs->subdev; break; default: dev_dbg(isp->dev, "unknown subdev probed\n"); @@ -1524,21 +1468,17 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i isp->max_isr_latency = ATOMISP_MAX_ISR_LATENCY; /* Load isp firmware from user space */ - if (!defer_fw_load) { - isp->firmware = atomisp_load_firmware(isp); - if (!isp->firmware) { - err = -ENOENT; - dev_dbg(&pdev->dev, "Firmware load failed\n"); - goto load_fw_fail; - } + isp->firmware = atomisp_load_firmware(isp); + if (!isp->firmware) { + err = -ENOENT; + dev_dbg(&pdev->dev, "Firmware load failed\n"); + goto load_fw_fail; + } - err = sh_css_check_firmware_version(isp->dev, isp->firmware->data); - if (err) { - dev_dbg(&pdev->dev, "Firmware version check failed\n"); - goto fw_validation_fail; - } - } else { - dev_info(&pdev->dev, "Firmware load will be deferred\n"); + err = sh_css_check_firmware_version(isp->dev, isp->firmware->data); + if (err) { + dev_dbg(&pdev->dev, "Firmware version check failed\n"); + goto fw_validation_fail; } pci_set_master(pdev); @@ -1603,6 +1543,26 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i /* save the iunit context only once after all the values are init'ed. */ atomisp_save_iunit_reg(isp); + /* + * The atomisp does not use standard PCI power-management through the + * PCI config space. Instead this driver directly tells the P-Unit to + * disable the ISP over the IOSF. The standard PCI subsystem pm_ops will + * try to access the config space before (resume) / after (suspend) this + * driver has turned the ISP on / off, resulting in the following errors: + * + * "Unable to change power state from D0 to D3hot, device inaccessible" + * "Unable to change power state from D3cold to D0, device inaccessible" + * + * To avoid these errors override the pm_domain so that all the PCI + * subsys suspend / resume handling is skipped. + */ + isp->pm_domain.ops.runtime_suspend = atomisp_power_off; + isp->pm_domain.ops.runtime_resume = atomisp_power_on; + isp->pm_domain.ops.suspend = atomisp_suspend; + isp->pm_domain.ops.resume = atomisp_resume; + + dev_pm_domain_set(&pdev->dev, &isp->pm_domain); + pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); @@ -1618,14 +1578,10 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i } /* Load firmware into ISP memory */ - if (!defer_fw_load) { - err = atomisp_css_load_firmware(isp); - if (err) { - dev_err(&pdev->dev, "Failed to init css.\n"); - goto css_init_fail; - } - } else { - dev_dbg(&pdev->dev, "Skip css init.\n"); + err = atomisp_css_load_firmware(isp); + if (err) { + dev_err(&pdev->dev, "Failed to init css.\n"); + goto css_init_fail; } /* Clear FW image from memory */ release_firmware(isp->firmware); @@ -1645,6 +1601,7 @@ css_init_fail: request_irq_fail: hmm_cleanup(); pm_runtime_get_noresume(&pdev->dev); + dev_pm_domain_set(&pdev->dev, NULL); atomisp_unregister_entities(isp); register_entities_fail: atomisp_uninitialize_modules(isp); @@ -1697,6 +1654,7 @@ static void atomisp_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); + dev_pm_domain_set(&pdev->dev, NULL); cpu_latency_qos_remove_request(&isp->pm_qos); atomisp_msi_irq_uninit(isp); @@ -1721,17 +1679,8 @@ static const struct pci_device_id atomisp_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); -static const struct dev_pm_ops atomisp_pm_ops = { - .runtime_suspend = atomisp_power_off, - .runtime_resume = atomisp_power_on, - .suspend = atomisp_suspend, - .resume = atomisp_resume, -}; static struct pci_driver atomisp_pci_driver = { - .driver = { - .pm = &atomisp_pm_ops, - }, .name = "atomisp-isp2", .id_table = atomisp_pci_tbl, .probe = atomisp_pci_probe, diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h index a313e1dc7c71..d65fe9ec9049 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h @@ -34,8 +34,6 @@ void isys2401_dma_reg_store(const isys2401_dma_ID_t dma_id, reg_loc = ISYS2401_DMA_BASE[dma_id] + (reg * sizeof(hrt_data)); - ia_css_print("isys dma store at addr(0x%x) val(%u)\n", reg_loc, - (unsigned int)value); ia_css_device_store_uint32(reg_loc, value); } diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c index 6620f091442f..d9cdfbc50197 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c @@ -28,10 +28,18 @@ typedef hive_uedge *hive_wide; /* Copied from SDK: sim_semantics.c */ /* subword bits move like this: MSB[____xxxx____]LSB -> MSB[00000000xxxx]LSB */ -#define SUBWORD(w, start, end) (((w) & (((1ULL << ((end) - 1)) - 1) << 1 | 1)) >> (start)) +static inline hive_uedge +subword(hive_uedge w, unsigned int start, unsigned int end) +{ + return (w & (((1ULL << (end - 1)) - 1) << 1 | 1)) >> start; +} /* inverse subword bits move like this: MSB[xxxx____xxxx]LSB -> MSB[xxxx0000xxxx]LSB */ -#define INV_SUBWORD(w, start, end) ((w) & (~(((1ULL << ((end) - 1)) - 1) << 1 | 1) | ((1ULL << (start)) - 1))) +static inline hive_uedge +inv_subword(hive_uedge w, unsigned int start, unsigned int end) +{ + return w & (~(((1ULL << (end - 1)) - 1) << 1 | 1) | ((1ULL << start) - 1)); +} #define uedge_bits (8 * sizeof(hive_uedge)) #define move_lower_bits(target, target_bit, src, src_bit) move_subword(target, target_bit, src, 0, src_bit) @@ -50,18 +58,18 @@ move_subword( unsigned int start_bit = target_bit % uedge_bits; unsigned int subword_width = src_end - src_start; - hive_uedge src_subword = SUBWORD(src, src_start, src_end); + hive_uedge src_subword = subword(src, src_start, src_end); if (subword_width + start_bit > uedge_bits) { /* overlap */ hive_uedge old_val1; - hive_uedge old_val0 = INV_SUBWORD(target[start_elem], start_bit, uedge_bits); + hive_uedge old_val0 = inv_subword(target[start_elem], start_bit, uedge_bits); target[start_elem] = old_val0 | (src_subword << start_bit); - old_val1 = INV_SUBWORD(target[start_elem + 1], 0, + old_val1 = inv_subword(target[start_elem + 1], 0, subword_width + start_bit - uedge_bits); target[start_elem + 1] = old_val1 | (src_subword >> (uedge_bits - start_bit)); } else { - hive_uedge old_val = INV_SUBWORD(target[start_elem], start_bit, + hive_uedge old_val = inv_subword(target[start_elem], start_bit, start_bit + subword_width); target[start_elem] = old_val | (src_subword << start_bit); diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 726cb7aa4ecd..93789500416f 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -97,9 +97,6 @@ */ #define JPEG_BYTES (16 * 1024 * 1024) -#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \ - (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis)) - struct sh_css my_css; int __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL; @@ -3743,7 +3740,9 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, * The SP will read the params after it got * empty 3a and dis */ - if (STATS_ENABLED(stage)) { + if (stage->binary && stage->binary->info && + (stage->binary->info->sp.enable.s3a || + stage->binary->info->sp.enable.dis)) { /* there is a stage that needs it */ return_err = ia_css_bufq_enqueue_buffer(thread_id, queue_id, diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index f08564f58242..588f2adab058 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -98,17 +98,27 @@ #include "sh_css_frac.h" #include "ia_css_bufq.h" -#define FPNTBL_BYTES(binary) \ - (sizeof(char) * (binary)->in_frame_info.res.height * \ - (binary)->in_frame_info.padded_width) +static size_t fpntbl_bytes(const struct ia_css_binary *binary) +{ + return array3_size(sizeof(char), + binary->in_frame_info.res.height, + binary->in_frame_info.padded_width); +} -#define SCTBL_BYTES(binary) \ - (sizeof(unsigned short) * (binary)->sctbl_height * \ - (binary)->sctbl_aligned_width_per_color * IA_CSS_SC_NUM_COLORS) +static size_t sctbl_bytes(const struct ia_css_binary *binary) +{ + return size_mul(sizeof(unsigned short), + array3_size(binary->sctbl_height, + binary->sctbl_aligned_width_per_color, + IA_CSS_SC_NUM_COLORS)); +} -#define MORPH_PLANE_BYTES(binary) \ - (SH_CSS_MORPH_TABLE_ELEM_BYTES * (binary)->morph_tbl_aligned_width * \ - (binary)->morph_tbl_height) +static size_t morph_plane_bytes(const struct ia_css_binary *binary) +{ + return array3_size(SH_CSS_MORPH_TABLE_ELEM_BYTES, + binary->morph_tbl_aligned_width, + binary->morph_tbl_height); +} /* We keep a second copy of the ptr struct for the SP to access. Again, this would not be necessary on the chip. */ @@ -3279,7 +3289,7 @@ sh_css_params_write_to_ddr_internal( if (binary->info->sp.enable.fpnr) { buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl, &ddr_map_size->fpn_tbl, - (size_t)(FPNTBL_BYTES(binary)), + fpntbl_bytes(binary), params->config_changed[IA_CSS_FPN_ID], &err); if (err) { @@ -3304,7 +3314,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced = reallocate_buffer(&ddr_map->sc_tbl, &ddr_map_size->sc_tbl, - SCTBL_BYTES(binary), + sctbl_bytes(binary), params->sc_table_changed, &err); if (err) { @@ -3538,8 +3548,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced |= reallocate_buffer(virt_addr_tetra_x[i], virt_size_tetra_x[i], - (size_t) - (MORPH_PLANE_BYTES(binary)), + morph_plane_bytes(binary), params->morph_table_changed, &err); if (err) { @@ -3549,8 +3558,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced |= reallocate_buffer(virt_addr_tetra_y[i], virt_size_tetra_y[i], - (size_t) - (MORPH_PLANE_BYTES(binary)), + morph_plane_bytes(binary), params->morph_table_changed, &err); if (err) { diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig index 1571eab31926..9faf9d2d4001 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/Kconfig +++ b/drivers/staging/media/av7110/Kconfig @@ -5,7 +5,7 @@ config DVB_AV7110_IR default DVB_AV7110 config DVB_AV7110 - tristate "AV7110 cards (DEPRECATED)" + tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV @@ -35,13 +35,10 @@ config DVB_AV7110 kernel image by adding the filename to the EXTRA_FIRMWARE configuration option string. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. config DVB_AV7110_OSD - bool "AV7110 OSD support (DEPRECATED)" + bool "AV7110 OSD support" depends on DVB_AV7110 default y if DVB_AV7110=y || DVB_AV7110=m help @@ -52,13 +49,10 @@ config DVB_AV7110_OSD Anyway, some popular DVB software like VDR uses this OSD to render its menus, so say Y if you want to use this software. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - All other people say N. config DVB_BUDGET_PATCH - tristate "AV7110 cards with Budget Patch (DEPRECATED)" + tristate "AV7110 cards with Budget Patch" depends on DVB_BUDGET_CORE && I2C depends on DVB_AV7110 select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT @@ -74,9 +68,6 @@ config DVB_BUDGET_PATCH standard AV7110 driver prior to loading this driver. - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the @@ -89,7 +80,7 @@ if DVB_AV7110 # it if we drop support for AV7110, as no other driver will use it. config DVB_SP8870 - tristate "Spase sp8870 based (DEPRECATED)" + tristate "Spase sp8870 based" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help @@ -100,7 +91,4 @@ config DVB_SP8870 download/extract it, and then copy it to /usr/lib/hotplug/firmware or /lib/firmware (depending on configuration of firmware hotplug). - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - endif diff --git a/drivers/staging/media/deprecated/saa7146/av7110/Makefile b/drivers/staging/media/av7110/Makefile index c04cd0a59109..307b267598ea 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/Makefile +++ b/drivers/staging/media/av7110/Makefile @@ -18,6 +18,5 @@ obj-$(CONFIG_DVB_SP8870) += sp8870.o ccflags-y += -I $(srctree)/drivers/media/dvb-frontends ccflags-y += -I $(srctree)/drivers/media/tuners +ccflags-y += -I $(srctree)/drivers/media/pci/ttpci ccflags-y += -I $(srctree)/drivers/media/common -ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/ttpci -ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/common diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO new file mode 100644 index 000000000000..60062d8441b3 --- /dev/null +++ b/drivers/staging/media/av7110/TODO @@ -0,0 +1,3 @@ +- This driver is too old and relies on a different API. + Drop it from Kernel on a couple of versions. +- Cleanup patches for the drivers here won't be accepted. diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst index 33b5363317f1..33b5363317f1 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst +++ b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst index 74093df92a68..74093df92a68 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst +++ b/drivers/staging/media/av7110/audio-channel-select.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst index a0ebb0278260..a0ebb0278260 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst +++ b/drivers/staging/media/av7110/audio-clear-buffer.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst index a2e9850f37f2..a2e9850f37f2 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst +++ b/drivers/staging/media/av7110/audio-continue.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst index 77857d578e83..77857d578e83 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst +++ b/drivers/staging/media/av7110/audio-fclose.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst index 774daaab3bad..774daaab3bad 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst +++ b/drivers/staging/media/av7110/audio-fopen.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst index 7b096ac2b6c4..7b096ac2b6c4 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst +++ b/drivers/staging/media/av7110/audio-fwrite.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst index 6d9eb71dad17..6d9eb71dad17 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst +++ b/drivers/staging/media/av7110/audio-get-capabilities.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst index 7ae8db2e65e9..7ae8db2e65e9 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst +++ b/drivers/staging/media/av7110/audio-get-status.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst index d37d1ddce4df..d37d1ddce4df 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst +++ b/drivers/staging/media/av7110/audio-pause.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst index e591930b6ca7..e591930b6ca7 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst +++ b/drivers/staging/media/av7110/audio-play.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst index 6a0c0f365eb1..6a0c0f365eb1 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst +++ b/drivers/staging/media/av7110/audio-select-source.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst index 85a8016bf025..85a8016bf025 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst +++ b/drivers/staging/media/av7110/audio-set-av-sync.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst index 80d551a2053a..80d551a2053a 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst +++ b/drivers/staging/media/av7110/audio-set-bypass-mode.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst index 39ad846d412d..39ad846d412d 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst +++ b/drivers/staging/media/av7110/audio-set-id.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst index 45dbdf4801e0..45dbdf4801e0 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst +++ b/drivers/staging/media/av7110/audio-set-mixer.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst index 987751f92967..987751f92967 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst +++ b/drivers/staging/media/av7110/audio-set-mute.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst index 77d73c74882f..77d73c74882f 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst +++ b/drivers/staging/media/av7110/audio-set-streamtype.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst index d77f786fd797..d77f786fd797 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst +++ b/drivers/staging/media/av7110/audio-stop.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst index aa753336b31f..aa753336b31f 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio.rst +++ b/drivers/staging/media/av7110/audio.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst index 4744529136a8..4744529136a8 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst +++ b/drivers/staging/media/av7110/audio_data_types.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst index fa5ba9539caf..fa5ba9539caf 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst +++ b/drivers/staging/media/av7110/audio_function_calls.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c index df81a9b744c2..df81a9b744c2 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110.c +++ b/drivers/staging/media/av7110/av7110.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h index 9fde69b38f1c..809d938ae166 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110.h +++ b/drivers/staging/media/av7110/av7110.h @@ -33,7 +33,7 @@ #include "stv0297.h" #include "l64781.h" -#include "saa7146_vv.h" +#include <media/drv-intf/saa7146_vv.h> #define ANALOG_TUNER_VES1820 1 diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c index 0bf513c26b6b..0bf513c26b6b 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c +++ b/drivers/staging/media/av7110/av7110_av.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h b/drivers/staging/media/av7110/av7110_av.h index 71bbd4391f57..71bbd4391f57 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h +++ b/drivers/staging/media/av7110/av7110_av.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c index c1338e074a3d..c1338e074a3d 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c +++ b/drivers/staging/media/av7110/av7110_ca.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h b/drivers/staging/media/av7110/av7110_ca.h index a6e3f2955730..a6e3f2955730 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h +++ b/drivers/staging/media/av7110/av7110_ca.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c b/drivers/staging/media/av7110/av7110_hw.c index 93ca31e38ddd..93ca31e38ddd 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c +++ b/drivers/staging/media/av7110/av7110_hw.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h b/drivers/staging/media/av7110/av7110_hw.h index 6380d8950c69..6380d8950c69 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h +++ b/drivers/staging/media/av7110/av7110_hw.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c b/drivers/staging/media/av7110/av7110_ipack.c index 30330ed01ce8..30330ed01ce8 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c +++ b/drivers/staging/media/av7110/av7110_ipack.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h b/drivers/staging/media/av7110/av7110_ipack.h index 943ec899bb93..943ec899bb93 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h +++ b/drivers/staging/media/av7110/av7110_ipack.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c index a851ba328e4a..a851ba328e4a 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c +++ b/drivers/staging/media/av7110/av7110_ir.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c b/drivers/staging/media/av7110/av7110_v4l.c index c89f536f699c..c89f536f699c 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c +++ b/drivers/staging/media/av7110/av7110_v4l.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c b/drivers/staging/media/av7110/budget-patch.c index d173c8ade6a7..d173c8ade6a7 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c +++ b/drivers/staging/media/av7110/budget-patch.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c b/drivers/staging/media/av7110/dvb_filter.c index 8c2eca5dcdc9..8c2eca5dcdc9 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c +++ b/drivers/staging/media/av7110/dvb_filter.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h b/drivers/staging/media/av7110/dvb_filter.h index 67a3c6333bca..67a3c6333bca 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h +++ b/drivers/staging/media/av7110/dvb_filter.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c index 9767159aeb9b..9767159aeb9b 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c +++ b/drivers/staging/media/av7110/sp8870.c diff --git a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h b/drivers/staging/media/av7110/sp8870.h index 5eacf39f425e..5eacf39f425e 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h +++ b/drivers/staging/media/av7110/sp8870.h diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst index a7730559bbb2..a7730559bbb2 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst +++ b/drivers/staging/media/av7110/video-clear-buffer.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst index cae9445eb3af..cae9445eb3af 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst +++ b/drivers/staging/media/av7110/video-command.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst index bc34bf3989e4..bc34bf3989e4 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst +++ b/drivers/staging/media/av7110/video-continue.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst index e71fa8d6965b..e71fa8d6965b 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst +++ b/drivers/staging/media/av7110/video-fast-forward.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst index 01d24d548439..01d24d548439 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst +++ b/drivers/staging/media/av7110/video-fclose.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst index 1371b083e4e8..1371b083e4e8 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst +++ b/drivers/staging/media/av7110/video-fopen.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst index 4321f257cb70..4321f257cb70 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst +++ b/drivers/staging/media/av7110/video-freeze.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst index a07fd7d7a40e..a07fd7d7a40e 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst +++ b/drivers/staging/media/av7110/video-fwrite.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst index 01e09f56656c..01e09f56656c 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst +++ b/drivers/staging/media/av7110/video-get-capabilities.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst index 90382bc36cfe..90382bc36cfe 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst +++ b/drivers/staging/media/av7110/video-get-event.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst index b48ac8c58a41..b48ac8c58a41 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst +++ b/drivers/staging/media/av7110/video-get-frame-count.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst index fedaff41be0b..fedaff41be0b 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst +++ b/drivers/staging/media/av7110/video-get-pts.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst index de34331c5bd1..de34331c5bd1 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst +++ b/drivers/staging/media/av7110/video-get-size.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst index 9b86fbf411d4..9b86fbf411d4 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst +++ b/drivers/staging/media/av7110/video-get-status.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst index 35ac8b98fdbf..35ac8b98fdbf 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst +++ b/drivers/staging/media/av7110/video-play.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst index 929a20985d53..929a20985d53 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst +++ b/drivers/staging/media/av7110/video-select-source.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst index 70249a6ba125..70249a6ba125 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst +++ b/drivers/staging/media/av7110/video-set-blank.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst index 1de4f40ae732..1de4f40ae732 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst +++ b/drivers/staging/media/av7110/video-set-display-format.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst index bb64e37ae081..bb64e37ae081 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst +++ b/drivers/staging/media/av7110/video-set-format.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst index 1f31c048bdbc..1f31c048bdbc 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst +++ b/drivers/staging/media/av7110/video-set-streamtype.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst index 1478fcc30cb8..1478fcc30cb8 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst +++ b/drivers/staging/media/av7110/video-slowmotion.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst index d25384222a20..d25384222a20 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst +++ b/drivers/staging/media/av7110/video-stillpicture.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst index 96f61c5b48a2..96f61c5b48a2 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst +++ b/drivers/staging/media/av7110/video-stop.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst index 79bf3dfb8a32..79bf3dfb8a32 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst +++ b/drivers/staging/media/av7110/video-try-command.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video.rst b/drivers/staging/media/av7110/video.rst index 808705b769a1..808705b769a1 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video.rst +++ b/drivers/staging/media/av7110/video.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst index 20a897be5dca..20a897be5dca 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst +++ b/drivers/staging/media/av7110/video_function_calls.rst diff --git a/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst index c4557d328b7a..c4557d328b7a 100644 --- a/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst +++ b/drivers/staging/media/av7110/video_types.rst diff --git a/drivers/staging/media/deprecated/cpia2/Kconfig b/drivers/staging/media/deprecated/cpia2/Kconfig deleted file mode 100644 index ee3b25a759d4..000000000000 --- a/drivers/staging/media/deprecated/cpia2/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_CPIA2 - tristate "CPiA2 Video For Linux (DEPRECATED)" - depends on USB && VIDEO_DEV - help - This is the video4linux driver for cameras based on Vision's CPiA2 - (Colour Processor Interface ASIC), such as the Digital Blue QX5 - Microscope. If you have one of these cameras, say Y here - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - This driver is also available as a module (cpia2). diff --git a/drivers/staging/media/deprecated/cpia2/Makefile b/drivers/staging/media/deprecated/cpia2/Makefile deleted file mode 100644 index 05664141f4d7..000000000000 --- a/drivers/staging/media/deprecated/cpia2/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -cpia2-objs := cpia2_v4l.o cpia2_usb.o cpia2_core.o - -obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o diff --git a/drivers/staging/media/deprecated/cpia2/TODO b/drivers/staging/media/deprecated/cpia2/TODO deleted file mode 100644 index 92ac8718d164..000000000000 --- a/drivers/staging/media/deprecated/cpia2/TODO +++ /dev/null @@ -1,6 +0,0 @@ -The cpia2 driver does not use the vb2 framework for streaming -video, instead it implements this in the driver. - -To prevent removal of this driver early 2023 it has to be -converted to use vb2. Contact the linux-media@vger.kernel.org -mailing list if you want to do this. diff --git a/drivers/staging/media/deprecated/cpia2/cpia2.h b/drivers/staging/media/deprecated/cpia2/cpia2.h deleted file mode 100644 index 57b7f1ea68da..000000000000 --- a/drivers/staging/media/deprecated/cpia2/cpia2.h +++ /dev/null @@ -1,475 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/**************************************************************************** - * - * Filename: cpia2.h - * - * Copyright 2001, STMicrolectronics, Inc. - * - * Contact: steve.miller@st.com - * - * Description: - * This is a USB driver for CPiA2 based video cameras. - * - * This driver is modelled on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - ****************************************************************************/ - -#ifndef __CPIA2_H__ -#define __CPIA2_H__ - -#include <linux/videodev2.h> -#include <linux/usb.h> -#include <linux/poll.h> -#include <media/v4l2-common.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ctrls.h> - -#include "cpia2_registers.h" - -/* define for verbose debug output */ -//#define _CPIA2_DEBUG_ - -/*** - * Image defines - ***/ - -/* Misc constants */ -#define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */ - -/* USB Transfer mode */ -#define XFER_ISOC 0 -#define XFER_BULK 1 - -/* USB Alternates */ -#define USBIF_CMDONLY 0 -#define USBIF_BULK 1 -#define USBIF_ISO_1 2 /* 128 bytes/ms */ -#define USBIF_ISO_2 3 /* 384 bytes/ms */ -#define USBIF_ISO_3 4 /* 640 bytes/ms */ -#define USBIF_ISO_4 5 /* 768 bytes/ms */ -#define USBIF_ISO_5 6 /* 896 bytes/ms */ -#define USBIF_ISO_6 7 /* 1023 bytes/ms */ - -/* Flicker Modes */ -#define NEVER_FLICKER 0 -#define FLICKER_60 60 -#define FLICKER_50 50 - -/* Debug flags */ -#define DEBUG_NONE 0 -#define DEBUG_REG 0x00000001 -#define DEBUG_DUMP_PATCH 0x00000002 -#define DEBUG_DUMP_REGS 0x00000004 - -/*** - * Video frame sizes - ***/ -enum { - VIDEOSIZE_VGA = 0, /* 640x480 */ - VIDEOSIZE_CIF, /* 352x288 */ - VIDEOSIZE_QVGA, /* 320x240 */ - VIDEOSIZE_QCIF, /* 176x144 */ - VIDEOSIZE_288_216, - VIDEOSIZE_256_192, - VIDEOSIZE_224_168, - VIDEOSIZE_192_144, -}; - -#define STV_IMAGE_CIF_ROWS 288 -#define STV_IMAGE_CIF_COLS 352 - -#define STV_IMAGE_QCIF_ROWS 144 -#define STV_IMAGE_QCIF_COLS 176 - -#define STV_IMAGE_VGA_ROWS 480 -#define STV_IMAGE_VGA_COLS 640 - -#define STV_IMAGE_QVGA_ROWS 240 -#define STV_IMAGE_QVGA_COLS 320 - -#define JPEG_MARKER_COM (1<<6) /* Comment segment */ - -/*** - * Enums - ***/ -/* Sensor types available with cpia2 asics */ -enum sensors { - CPIA2_SENSOR_410, - CPIA2_SENSOR_500 -}; - -/* Asic types available in the CPiA2 architecture */ -#define CPIA2_ASIC_672 0x67 - -/* Device types (stv672, stv676, etc) */ -#define DEVICE_STV_672 0x0001 -#define DEVICE_STV_676 0x0002 - -enum frame_status { - FRAME_EMPTY, - FRAME_READING, /* In the process of being grabbed into */ - FRAME_READY, /* Ready to be read */ - FRAME_ERROR, -}; - -/*** - * Register access (for USB request byte) - ***/ -enum { - CAMERAACCESS_SYSTEM = 0, - CAMERAACCESS_VC, - CAMERAACCESS_VP, - CAMERAACCESS_IDATA -}; - -#define CAMERAACCESS_TYPE_BLOCK 0x00 -#define CAMERAACCESS_TYPE_RANDOM 0x04 -#define CAMERAACCESS_TYPE_MASK 0x08 -#define CAMERAACCESS_TYPE_REPEAT 0x0C - -#define TRANSFER_READ 0 -#define TRANSFER_WRITE 1 - -#define DEFAULT_ALT USBIF_ISO_6 -#define DEFAULT_BRIGHTNESS 0x46 -#define DEFAULT_CONTRAST 0x93 -#define DEFAULT_SATURATION 0x7f - -/* Power state */ -#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER -#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER - - -/******** - * Commands - *******/ -enum { - CPIA2_CMD_NONE = 0, - CPIA2_CMD_GET_VERSION, - CPIA2_CMD_GET_PNP_ID, - CPIA2_CMD_GET_ASIC_TYPE, - CPIA2_CMD_GET_SENSOR, - CPIA2_CMD_GET_VP_DEVICE, - CPIA2_CMD_GET_VP_BRIGHTNESS, - CPIA2_CMD_SET_VP_BRIGHTNESS, - CPIA2_CMD_GET_CONTRAST, - CPIA2_CMD_SET_CONTRAST, - CPIA2_CMD_GET_VP_SATURATION, - CPIA2_CMD_SET_VP_SATURATION, - CPIA2_CMD_GET_VP_GPIO_DIRECTION, - CPIA2_CMD_SET_VP_GPIO_DIRECTION, - CPIA2_CMD_GET_VP_GPIO_DATA, - CPIA2_CMD_SET_VP_GPIO_DATA, - CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, - CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - CPIA2_CMD_GET_VC_MP_GPIO_DATA, - CPIA2_CMD_SET_VC_MP_GPIO_DATA, - CPIA2_CMD_ENABLE_PACKET_CTRL, - CPIA2_CMD_GET_FLICKER_MODES, - CPIA2_CMD_SET_FLICKER_MODES, - CPIA2_CMD_RESET_FIFO, /* clear fifo and enable stream block */ - CPIA2_CMD_SET_HI_POWER, - CPIA2_CMD_SET_LOW_POWER, - CPIA2_CMD_CLEAR_V2W_ERR, - CPIA2_CMD_SET_USER_MODE, - CPIA2_CMD_GET_USER_MODE, - CPIA2_CMD_FRAMERATE_REQ, - CPIA2_CMD_SET_COMPRESSION_STATE, - CPIA2_CMD_GET_WAKEUP, - CPIA2_CMD_SET_WAKEUP, - CPIA2_CMD_GET_PW_CONTROL, - CPIA2_CMD_SET_PW_CONTROL, - CPIA2_CMD_GET_SYSTEM_CTRL, - CPIA2_CMD_SET_SYSTEM_CTRL, - CPIA2_CMD_GET_VP_SYSTEM_STATE, - CPIA2_CMD_GET_VP_SYSTEM_CTRL, - CPIA2_CMD_SET_VP_SYSTEM_CTRL, - CPIA2_CMD_GET_VP_EXP_MODES, - CPIA2_CMD_SET_VP_EXP_MODES, - CPIA2_CMD_GET_DEVICE_CONFIG, - CPIA2_CMD_SET_DEVICE_CONFIG, - CPIA2_CMD_SET_SERIAL_ADDR, - CPIA2_CMD_SET_SENSOR_CR1, - CPIA2_CMD_GET_VC_CONTROL, - CPIA2_CMD_SET_VC_CONTROL, - CPIA2_CMD_SET_TARGET_KB, - CPIA2_CMD_SET_DEF_JPEG_OPT, - CPIA2_CMD_REHASH_VP4, - CPIA2_CMD_GET_USER_EFFECTS, - CPIA2_CMD_SET_USER_EFFECTS -}; - -enum user_cmd { - COMMAND_NONE = 0x00000001, - COMMAND_SET_FPS = 0x00000002, - COMMAND_SET_COLOR_PARAMS = 0x00000004, - COMMAND_GET_COLOR_PARAMS = 0x00000008, - COMMAND_SET_FORMAT = 0x00000010, /* size, etc */ - COMMAND_SET_FLICKER = 0x00000020 -}; - -/*** - * Some defines specific to the 676 chip - ***/ -#define CAMACC_CIF 0x01 -#define CAMACC_VGA 0x02 -#define CAMACC_QCIF 0x04 -#define CAMACC_QVGA 0x08 - - -struct cpia2_register { - u8 index; - u8 value; -}; - -struct cpia2_reg_mask { - u8 index; - u8 and_mask; - u8 or_mask; - u8 fill; -}; - -struct cpia2_command { - u32 command; - u8 req_mode; /* (Block or random) | registerBank */ - u8 reg_count; - u8 direction; - u8 start; - union reg_types { - struct cpia2_register registers[32]; - struct cpia2_reg_mask masks[16]; - u8 block_data[64]; - u8 *patch_data; /* points to function defined block */ - } buffer; -}; - -struct camera_params { - struct { - u8 firmware_revision_hi; /* For system register set (bank 0) */ - u8 firmware_revision_lo; - u8 asic_id; /* Video Compressor set (bank 1) */ - u8 asic_rev; - u8 vp_device_hi; /* Video Processor set (bank 2) */ - u8 vp_device_lo; - u8 sensor_flags; - u8 sensor_rev; - } version; - - struct { - u32 device_type; /* enumerated from vendor/product ids. - * Currently, either STV_672 or STV_676 */ - u16 vendor; - u16 product; - u16 device_revision; - } pnp_id; - - struct { - u8 brightness; /* CPIA2_VP_EXPOSURE_TARGET */ - u8 contrast; /* Note: this is CPIA2_VP_YRANGE */ - u8 saturation; /* CPIA2_VP_SATURATION */ - } color_params; - - struct { - u8 cam_register; - u8 flicker_mode_req; /* 1 if flicker on, else never flicker */ - } flicker_control; - - struct { - u8 jpeg_options; - u8 creep_period; - u8 user_squeeze; - u8 inhibit_htables; - } compression; - - struct { - u8 ohsize; /* output image size */ - u8 ovsize; - u8 hcrop; /* cropping start_pos/4 */ - u8 vcrop; - u8 hphase; /* scaling registers */ - u8 vphase; - u8 hispan; - u8 vispan; - u8 hicrop; - u8 vicrop; - u8 hifraction; - u8 vifraction; - } image_size; - - struct { - int width; /* actual window width */ - int height; /* actual window height */ - } roi; - - struct { - u8 video_mode; - u8 frame_rate; - u8 video_size; /* Not a register, just a convenience for cropped sizes */ - u8 gpio_direction; - u8 gpio_data; - u8 system_ctrl; - u8 system_state; - u8 lowlight_boost; /* Bool: 0 = off, 1 = on */ - u8 device_config; - u8 exposure_modes; - u8 user_effects; - } vp_params; - - struct { - u8 pw_control; - u8 wakeup; - u8 vc_control; - u8 vc_mp_direction; - u8 vc_mp_data; - u8 quality; - } vc_params; - - struct { - u8 power_mode; - u8 system_ctrl; - u8 stream_mode; /* This is the current alternate for usb drivers */ - u8 allow_corrupt; - } camera_state; -}; - -#define NUM_SBUF 2 - -struct cpia2_sbuf { - char *data; - struct urb *urb; -}; - -struct framebuf { - u64 ts; - unsigned long seq; - int num; - int length; - int max_length; - volatile enum frame_status status; - u8 *data; - struct framebuf *next; -}; - -struct camera_data { - /* locks */ - struct v4l2_device v4l2_dev; - struct mutex v4l2_lock; /* serialize file operations */ - struct v4l2_ctrl_handler hdl; - struct { - /* Lights control cluster */ - struct v4l2_ctrl *top_light; - struct v4l2_ctrl *bottom_light; - }; - struct v4l2_ctrl *usb_alt; - - /* camera status */ - int first_image_seen; - enum sensors sensor_type; - u8 flush; - struct v4l2_fh *stream_fh; - u8 mmapped; - int streaming; /* 0 = no, 1 = yes */ - int xfer_mode; /* XFER_BULK or XFER_ISOC */ - struct camera_params params; /* camera settings */ - - /* v4l */ - int video_size; /* VIDEO_SIZE_ */ - struct video_device vdev; /* v4l videodev */ - u32 width; - u32 height; /* Its size */ - __u32 pixelformat; /* Format fourcc */ - - /* USB */ - struct usb_device *dev; - unsigned char iface; - unsigned int cur_alt; - unsigned int old_alt; - struct cpia2_sbuf sbuf[NUM_SBUF]; /* Double buffering */ - - wait_queue_head_t wq_stream; - - /* Buffering */ - u32 frame_size; - int num_frames; - unsigned long frame_count; - u8 *frame_buffer; /* frame buffer data */ - struct framebuf *buffers; - struct framebuf * volatile curbuff; - struct framebuf *workbuff; - - /* MJPEG Extension */ - int APPn; /* Number of APP segment to be written, must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ -}; - -/* v4l */ -int cpia2_register_camera(struct camera_data *cam); -void cpia2_unregister_camera(struct camera_data *cam); -void cpia2_camera_release(struct v4l2_device *v4l2_dev); - -/* core */ -int cpia2_reset_camera(struct camera_data *cam); -int cpia2_set_low_power(struct camera_data *cam); -void cpia2_dbg_dump_registers(struct camera_data *cam); -int cpia2_match_video_size(int width, int height); -void cpia2_set_camera_state(struct camera_data *cam); -void cpia2_save_camera_state(struct camera_data *cam); -void cpia2_set_color_params(struct camera_data *cam); -void cpia2_set_brightness(struct camera_data *cam, unsigned char value); -void cpia2_set_contrast(struct camera_data *cam, unsigned char value); -void cpia2_set_saturation(struct camera_data *cam, unsigned char value); -int cpia2_set_flicker_mode(struct camera_data *cam, int mode); -void cpia2_set_format(struct camera_data *cam); -int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd); -int cpia2_do_command(struct camera_data *cam, - unsigned int command, - unsigned char direction, unsigned char param); -void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf); -struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf); -int cpia2_init_camera(struct camera_data *cam); -int cpia2_allocate_buffers(struct camera_data *cam); -void cpia2_free_buffers(struct camera_data *cam); -long cpia2_read(struct camera_data *cam, - char __user *buf, unsigned long count, int noblock); -__poll_t cpia2_poll(struct camera_data *cam, - struct file *filp, poll_table *wait); -int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma); -void cpia2_set_property_flip(struct camera_data *cam, int prop_val); -void cpia2_set_property_mirror(struct camera_data *cam, int prop_val); -int cpia2_set_gpio(struct camera_data *cam, unsigned char setting); -int cpia2_set_fps(struct camera_data *cam, int framerate); - -/* usb */ -int cpia2_usb_init(void); -void cpia2_usb_cleanup(void); -int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers, - u8 request, u8 start, u8 count, u8 direction); -int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate); -int cpia2_usb_stream_stop(struct camera_data *cam); -int cpia2_usb_stream_pause(struct camera_data *cam); -int cpia2_usb_stream_resume(struct camera_data *cam); -int cpia2_usb_change_streaming_alternate(struct camera_data *cam, - unsigned int alt); - - -/* ----------------------- debug functions ---------------------- */ -#ifdef _CPIA2_DEBUG_ -#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args) -#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args) -#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args) -#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args) -#else -#define ALOG(fmt,args...) printk(fmt,##args) -#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args) -#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args) -#define DBG(fmn,args...) do {} while(0) -#endif -/* No function or lineno, for shorter lines */ -#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args) - -#endif diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_core.c b/drivers/staging/media/deprecated/cpia2/cpia2_core.c deleted file mode 100644 index b5a2d06fb356..000000000000 --- a/drivers/staging/media/deprecated/cpia2/cpia2_core.c +++ /dev/null @@ -1,2434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/**************************************************************************** - * - * Filename: cpia2_core.c - * - * Copyright 2001, STMicrolectronics, Inc. - * Contact: steve.miller@st.com - * - * Description: - * This is a USB driver for CPia2 based video cameras. - * The infrastructure of this driver is based on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox <alan@lxorguk.ukuu.org.uk> - * - ****************************************************************************/ - -#include "cpia2.h" - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/firmware.h> -#include <linux/sched/signal.h> - -#define FIRMWARE "cpia2/stv0672_vp4.bin" -MODULE_FIRMWARE(FIRMWARE); - -/* #define _CPIA2_DEBUG_ */ - -#ifdef _CPIA2_DEBUG_ - -static const char *block_name[] = { - "System", - "VC", - "VP", - "IDATA" -}; -#endif - -static unsigned int debugs_on; /* default 0 - DEBUG_REG */ - - -/****************************************************************************** - * - * Forward Declarations - * - *****************************************************************************/ -static int apply_vp_patch(struct camera_data *cam); -static int set_default_user_mode(struct camera_data *cam); -static int set_vw_size(struct camera_data *cam, int size); -static int configure_sensor(struct camera_data *cam, - int reqwidth, int reqheight); -static int config_sensor_410(struct camera_data *cam, - int reqwidth, int reqheight); -static int config_sensor_500(struct camera_data *cam, - int reqwidth, int reqheight); -static int set_all_properties(struct camera_data *cam); -static void wake_system(struct camera_data *cam); -static void set_lowlight_boost(struct camera_data *cam); -static void reset_camera_struct(struct camera_data *cam); -static int cpia2_set_high_power(struct camera_data *cam); - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - /* Round it off to PAGE_SIZE */ - size = PAGE_ALIGN(size); - - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - - while ((long)size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - size = PAGE_ALIGN(size); - - adr = (unsigned long) mem; - while ((long)size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - -/****************************************************************************** - * - * cpia2_do_command - * - * Send an arbitrary command to the camera. For commands that read from - * the camera, copy the buffers into the proper param structures. - *****************************************************************************/ -int cpia2_do_command(struct camera_data *cam, - u32 command, u8 direction, u8 param) -{ - int retval = 0; - struct cpia2_command cmd; - unsigned int device = cam->params.pnp_id.device_type; - - cmd.command = command; - cmd.reg_count = 2; /* default */ - cmd.direction = direction; - - /*** - * Set up the command. - ***/ - switch (command) { - case CPIA2_CMD_GET_VERSION: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.start = CPIA2_SYSTEM_DEVICE_HI; - break; - case CPIA2_CMD_GET_PNP_ID: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 8; - cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI; - break; - case CPIA2_CMD_GET_ASIC_TYPE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.start = CPIA2_VC_ASIC_ID; - break; - case CPIA2_CMD_GET_SENSOR: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.start = CPIA2_VP_SENSOR_FLAGS; - break; - case CPIA2_CMD_GET_VP_DEVICE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.start = CPIA2_VP_DEVICEH; - break; - case CPIA2_CMD_SET_VP_BRIGHTNESS: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VP_BRIGHTNESS: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_EXPOSURE_TARGET; - else - cmd.start = CPIA2_VP5_EXPOSURE_TARGET; - break; - case CPIA2_CMD_SET_CONTRAST: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_CONTRAST: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_YRANGE; - break; - case CPIA2_CMD_SET_VP_SATURATION: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VP_SATURATION: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP_SATURATION; - else - cmd.start = CPIA2_VP5_MCUVSATURATION; - break; - case CPIA2_CMD_SET_VP_GPIO_DATA: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VP_GPIO_DATA: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_GPIO_DATA; - break; - case CPIA2_CMD_SET_VP_GPIO_DIRECTION: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VP_GPIO_DIRECTION: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_GPIO_DIRECTION; - break; - case CPIA2_CMD_SET_VC_MP_GPIO_DATA: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VC_MP_GPIO_DATA: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_MP_DATA; - break; - case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_MP_DIR; - break; - case CPIA2_CMD_ENABLE_PACKET_CTRL: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL; - cmd.reg_count = 1; - cmd.buffer.block_data[0] = param; - break; - case CPIA2_CMD_SET_FLICKER_MODES: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_FLICKER_MODES: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_FLICKER_MODES; - break; - case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */ - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.reg_count = 2; - cmd.start = 0; - cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; - cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | - CPIA2_VC_ST_CTRL_EOF_DETECT | - CPIA2_VC_ST_CTRL_FIFO_ENABLE; - break; - case CPIA2_CMD_SET_HI_POWER: - cmd.req_mode = - CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; - cmd.reg_count = 2; - cmd.buffer.registers[0].index = - CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.registers[1].index = - CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; - cmd.buffer.registers[1].value = - CPIA2_SYSTEM_CONTROL_HIGH_POWER; - break; - case CPIA2_CMD_SET_LOW_POWER: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.block_data[0] = 0; - break; - case CPIA2_CMD_CLEAR_V2W_ERR: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; - cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; - break; - case CPIA2_CMD_SET_USER_MODE: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_USER_MODE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_USER_MODE; - else - cmd.start = CPIA2_VP5_USER_MODE; - break; - case CPIA2_CMD_FRAMERATE_REQ: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_FRAMERATE_REQUEST; - else - cmd.start = CPIA2_VP5_FRAMERATE_REQUEST; - cmd.buffer.block_data[0] = param; - break; - case CPIA2_CMD_SET_WAKEUP: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_WAKEUP: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_WAKEUP; - break; - case CPIA2_CMD_SET_PW_CONTROL: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_PW_CONTROL: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_PW_CTRL; - break; - case CPIA2_CMD_GET_VP_SYSTEM_STATE: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_SYSTEMSTATE; - break; - case CPIA2_CMD_SET_SYSTEM_CTRL: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_SYSTEM_CTRL: - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; - break; - case CPIA2_CMD_SET_VP_SYSTEM_CTRL: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VP_SYSTEM_CTRL: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_SYSTEMCTRL; - break; - case CPIA2_CMD_SET_VP_EXP_MODES: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VP_EXP_MODES: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_EXPOSURE_MODES; - break; - case CPIA2_CMD_SET_DEVICE_CONFIG: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_DEVICE_CONFIG: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_DEVICE_CONFIG; - break; - case CPIA2_CMD_SET_SERIAL_ADDR: - cmd.buffer.block_data[0] = param; - cmd.req_mode = - CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 1; - cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR; - break; - case CPIA2_CMD_SET_SENSOR_CR1: - cmd.buffer.block_data[0] = param; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_SENSOR_CR1; - break; - case CPIA2_CMD_SET_VC_CONTROL: - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_VC_CONTROL: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.start = CPIA2_VC_VC_CTRL; - break; - case CPIA2_CMD_SET_TARGET_KB: - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.reg_count = 1; - cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB; - cmd.buffer.registers[0].value = param; - break; - case CPIA2_CMD_SET_DEF_JPEG_OPT: - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.reg_count = 4; - cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT; - cmd.buffer.registers[0].value = - CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE; - cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE; - cmd.buffer.registers[1].value = 20; - cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD; - cmd.buffer.registers[2].value = 2; - cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT; - cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT; - break; - case CPIA2_CMD_REHASH_VP4: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - cmd.start = CPIA2_VP_REHASH_VALUES; - cmd.buffer.block_data[0] = param; - break; - case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as - this register can also affect - flicker modes */ - cmd.buffer.block_data[0] = param; - fallthrough; - case CPIA2_CMD_GET_USER_EFFECTS: - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 1; - if (device == DEVICE_STV_672) - cmd.start = CPIA2_VP4_USER_EFFECTS; - else - cmd.start = CPIA2_VP5_USER_EFFECTS; - break; - default: - LOG("DoCommand received invalid command\n"); - return -EINVAL; - } - - retval = cpia2_send_command(cam, &cmd); - if (retval) { - return retval; - } - - /*** - * Now copy any results from a read into the appropriate param struct. - ***/ - switch (command) { - case CPIA2_CMD_GET_VERSION: - cam->params.version.firmware_revision_hi = - cmd.buffer.block_data[0]; - cam->params.version.firmware_revision_lo = - cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_PNP_ID: - cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) | - cmd.buffer.block_data[1]; - cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) | - cmd.buffer.block_data[3]; - cam->params.pnp_id.device_revision = - (cmd.buffer.block_data[4] << 8) | - cmd.buffer.block_data[5]; - if (cam->params.pnp_id.vendor == 0x553) { - if (cam->params.pnp_id.product == 0x100) { - cam->params.pnp_id.device_type = DEVICE_STV_672; - } else if (cam->params.pnp_id.product == 0x140 || - cam->params.pnp_id.product == 0x151) { - cam->params.pnp_id.device_type = DEVICE_STV_676; - } - } - break; - case CPIA2_CMD_GET_ASIC_TYPE: - cam->params.version.asic_id = cmd.buffer.block_data[0]; - cam->params.version.asic_rev = cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_SENSOR: - cam->params.version.sensor_flags = cmd.buffer.block_data[0]; - cam->params.version.sensor_rev = cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_VP_DEVICE: - cam->params.version.vp_device_hi = cmd.buffer.block_data[0]; - cam->params.version.vp_device_lo = cmd.buffer.block_data[1]; - break; - case CPIA2_CMD_GET_VP_GPIO_DATA: - cam->params.vp_params.gpio_data = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_GPIO_DIRECTION: - cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: - cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VC_MP_GPIO_DATA: - cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_FLICKER_MODES: - cam->params.flicker_control.cam_register = - cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_WAKEUP: - cam->params.vc_params.wakeup = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_PW_CONTROL: - cam->params.vc_params.pw_control = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_SYSTEM_CTRL: - cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_SYSTEM_STATE: - cam->params.vp_params.system_state = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_SYSTEM_CTRL: - cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VP_EXP_MODES: - cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_DEVICE_CONFIG: - cam->params.vp_params.device_config = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_VC_CONTROL: - cam->params.vc_params.vc_control = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_USER_MODE: - cam->params.vp_params.video_mode = cmd.buffer.block_data[0]; - break; - case CPIA2_CMD_GET_USER_EFFECTS: - cam->params.vp_params.user_effects = cmd.buffer.block_data[0]; - break; - default: - break; - } - return retval; -} - -/****************************************************************************** - * - * cpia2_send_command - * - *****************************************************************************/ - -#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read") -#define BINDEX(cmd) (cmd->req_mode & 0x03) - -int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd) -{ - u8 count; - u8 start; - u8 *buffer; - int retval; - - switch (cmd->req_mode & 0x0c) { - case CAMERAACCESS_TYPE_RANDOM: - count = cmd->reg_count * sizeof(struct cpia2_register); - start = 0; - buffer = (u8 *) & cmd->buffer; - if (debugs_on & DEBUG_REG) - DBG("%s Random: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - case CAMERAACCESS_TYPE_BLOCK: - count = cmd->reg_count; - start = cmd->start; - buffer = cmd->buffer.block_data; - if (debugs_on & DEBUG_REG) - DBG("%s Block: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - case CAMERAACCESS_TYPE_MASK: - count = cmd->reg_count * sizeof(struct cpia2_reg_mask); - start = 0; - buffer = (u8 *) & cmd->buffer; - if (debugs_on & DEBUG_REG) - DBG("%s Mask: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */ - count = cmd->reg_count; - start = cmd->start; - buffer = cmd->buffer.block_data; - if (debugs_on & DEBUG_REG) - DBG("%s Repeat: Register block %s\n", DIR(cmd), - block_name[BINDEX(cmd)]); - break; - default: - LOG("%s: invalid request mode\n",__func__); - return -EINVAL; - } - - retval = cpia2_usb_transfer_cmd(cam, - buffer, - cmd->req_mode, - start, count, cmd->direction); -#ifdef _CPIA2_DEBUG_ - if (debugs_on & DEBUG_REG) { - int i; - for (i = 0; i < cmd->reg_count; i++) { - if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK) - KINFO("%s Block: [0x%02X] = 0x%02X\n", - DIR(cmd), start + i, buffer[i]); - if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM) - KINFO("%s Random: [0x%02X] = 0x%02X\n", - DIR(cmd), cmd->buffer.registers[i].index, - cmd->buffer.registers[i].value); - } - } -#endif - - return retval; -}; - -/************* - * Functions to implement camera functionality - *************/ -/****************************************************************************** - * - * cpia2_get_version_info - * - *****************************************************************************/ -static void cpia2_get_version_info(struct camera_data *cam) -{ - cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0); -} - -/****************************************************************************** - * - * cpia2_reset_camera - * - * Called at least during the open process, sets up initial params. - *****************************************************************************/ -int cpia2_reset_camera(struct camera_data *cam) -{ - u8 tmp_reg; - int retval = 0; - int target_kb; - int i; - struct cpia2_command cmd; - - /*** - * VC setup - ***/ - retval = configure_sensor(cam, - cam->params.roi.width, - cam->params.roi.height); - if (retval < 0) { - ERR("Couldn't configure sensor, error=%d\n", retval); - return retval; - } - - /* Clear FIFO and route/enable stream block */ - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.direction = TRANSFER_WRITE; - cmd.reg_count = 2; - cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; - cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; - cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | - CPIA2_VC_ST_CTRL_DST_USB | - CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE; - - cpia2_send_command(cam, &cmd); - - cpia2_set_high_power(cam); - - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - /* Enable button notification */ - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; - cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL; - cmd.buffer.registers[0].value = - CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX; - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - } - - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - retval = apply_vp_patch(cam); - - /* wait for vp to go to sleep */ - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - /*** - * If this is a 676, apply VP5 fixes before we start streaming - ***/ - if (cam->params.pnp_id.device_type == DEVICE_STV_676) { - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; - - /* The following writes improve the picture */ - cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL; - cmd.buffer.registers[0].value = 0; /* reduce from the default - * rec 601 pedestal of 16 */ - cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE; - cmd.buffer.registers[1].value = 0x92; /* increase from 100% to - * (256/256 - 31) to fill - * available range */ - cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING; - cmd.buffer.registers[2].value = 0xFF; /* Increase from the - * default rec 601 ceiling - * of 240 */ - cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION; - cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec - * 601 100% level (128) - * to 145-192 */ - cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP; - cmd.buffer.registers[4].value = 0x80; /* Inhibit the - * anti-flicker */ - - /* The following 4 writes are a fix to allow QVGA to work at 30 fps */ - cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H; - cmd.buffer.registers[5].value = 0x01; - cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L; - cmd.buffer.registers[6].value = 0xE3; - cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA; - cmd.buffer.registers[7].value = 0x02; - cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA; - cmd.buffer.registers[8].value = 0xFC; - - cmd.direction = TRANSFER_WRITE; - cmd.reg_count = 9; - - cpia2_send_command(cam, &cmd); - } - - /* Activate all settings and start the data stream */ - /* Set user mode */ - set_default_user_mode(cam); - - /* Give VP time to wake up */ - schedule_timeout_interruptible(msecs_to_jiffies(100)); - - set_all_properties(cam); - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); - DBG("After SetAllProperties(cam), user mode is 0x%0X\n", - cam->params.vp_params.video_mode); - - /*** - * Set audio regulator off. This and the code to set the compresison - * state are too complex to form a CPIA2_CMD_, and seem to be somewhat - * intertwined. This stuff came straight from the windows driver. - ***/ - /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */ - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); - tmp_reg = cam->params.vp_params.system_ctrl; - cmd.buffer.registers[0].value = tmp_reg & - (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF)); - - cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); - cmd.buffer.registers[1].value = cam->params.vp_params.device_config | - CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE; - cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL; - cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG; - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; - cmd.reg_count = 2; - cmd.direction = TRANSFER_WRITE; - cmd.start = 0; - cpia2_send_command(cam, &cmd); - - /* Set the correct I2C address in the CPiA-2 system register */ - cpia2_do_command(cam, - CPIA2_CMD_SET_SERIAL_ADDR, - TRANSFER_WRITE, - CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR); - - /* Now have sensor access - set bit to turn the audio regulator off */ - cpia2_do_command(cam, - CPIA2_CMD_SET_SENSOR_CR1, - TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR); - - /* Set the correct I2C address in the CPiA-2 system register */ - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - cpia2_do_command(cam, - CPIA2_CMD_SET_SERIAL_ADDR, - TRANSFER_WRITE, - CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88 - else - cpia2_do_command(cam, - CPIA2_CMD_SET_SERIAL_ADDR, - TRANSFER_WRITE, - CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a - - /* increase signal drive strength */ - if (cam->params.pnp_id.device_type == DEVICE_STV_676) - cpia2_do_command(cam, - CPIA2_CMD_SET_VP_EXP_MODES, - TRANSFER_WRITE, - CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP); - - /* Start autoexposure */ - cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); - cmd.buffer.registers[0].value = cam->params.vp_params.device_config & - (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF); - - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); - cmd.buffer.registers[1].value = - cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL; - - cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG; - cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL; - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; - cmd.reg_count = 2; - cmd.direction = TRANSFER_WRITE; - - cpia2_send_command(cam, &cmd); - - /* Set compression state */ - cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0); - if (cam->params.compression.inhibit_htables) { - tmp_reg = cam->params.vc_params.vc_control | - CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; - } else { - tmp_reg = cam->params.vc_params.vc_control & - ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; - } - cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg); - - /* Set target size (kb) on vc - This is a heuristic based on the quality parameter and the raw - framesize in kB divided by 16 (the compression factor when the - quality is 100%) */ - target_kb = (cam->width * cam->height * 2 / 16384) * - cam->params.vc_params.quality / 100; - if (target_kb < 1) - target_kb = 1; - cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB, - TRANSFER_WRITE, target_kb); - - /* Wiggle VC Reset */ - /*** - * First read and wait a bit. - ***/ - for (i = 0; i < 50; i++) { - cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL, - TRANSFER_READ, 0); - } - - tmp_reg = cam->params.vc_params.pw_control; - tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N; - - cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); - - tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N; - cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); - - cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0); - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); - DBG("After VC RESET, user mode is 0x%0X\n", - cam->params.vp_params.video_mode); - - return retval; -} - -/****************************************************************************** - * - * cpia2_set_high_power - * - *****************************************************************************/ -static int cpia2_set_high_power(struct camera_data *cam) -{ - int i; - for (i = 0; i <= 50; i++) { - /* Read system status */ - cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0); - - /* If there is an error, clear it */ - if(cam->params.camera_state.system_ctrl & - CPIA2_SYSTEM_CONTROL_V2W_ERR) - cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR, - TRANSFER_WRITE, 0); - - /* Try to set high power mode */ - cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, - TRANSFER_WRITE, 1); - - /* Try to read something in VP to check if everything is awake */ - cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE, - TRANSFER_READ, 0); - if (cam->params.vp_params.system_state & - CPIA2_VP_SYSTEMSTATE_HK_ALIVE) { - break; - } else if (i == 50) { - cam->params.camera_state.power_mode = LO_POWER_MODE; - ERR("Camera did not wake up\n"); - return -EIO; - } - } - - DBG("System now in high power state\n"); - cam->params.camera_state.power_mode = HI_POWER_MODE; - return 0; -} - -/****************************************************************************** - * - * cpia2_set_low_power - * - *****************************************************************************/ -int cpia2_set_low_power(struct camera_data *cam) -{ - cam->params.camera_state.power_mode = LO_POWER_MODE; - cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0); - return 0; -} - -/****************************************************************************** - * - * apply_vp_patch - * - *****************************************************************************/ -static int cpia2_send_onebyte_command(struct camera_data *cam, - struct cpia2_command *cmd, - u8 start, u8 datum) -{ - cmd->buffer.block_data[0] = datum; - cmd->start = start; - cmd->reg_count = 1; - return cpia2_send_command(cam, cmd); -} - -static int apply_vp_patch(struct camera_data *cam) -{ - const struct firmware *fw; - const char fw_name[] = FIRMWARE; - int i, ret; - struct cpia2_command cmd; - - ret = request_firmware(&fw, fw_name, &cam->dev->dev); - if (ret) { - printk(KERN_ERR "cpia2: failed to load VP patch \"%s\"\n", - fw_name); - return ret; - } - - cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP; - cmd.direction = TRANSFER_WRITE; - - /* First send the start address... */ - cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */ - cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */ - - /* ... followed by the data payload */ - for (i = 2; i < fw->size; i += 64) { - cmd.start = 0x0C; /* Data */ - cmd.reg_count = min_t(uint, 64, fw->size - i); - memcpy(cmd.buffer.block_data, &fw->data[i], cmd.reg_count); - cpia2_send_command(cam, &cmd); - } - - /* Next send the start address... */ - cpia2_send_onebyte_command(cam, &cmd, 0x0A, fw->data[0]); /* hi */ - cpia2_send_onebyte_command(cam, &cmd, 0x0B, fw->data[1]); /* lo */ - - /* ... followed by the 'goto' command */ - cpia2_send_onebyte_command(cam, &cmd, 0x0D, 1); - - release_firmware(fw); - return 0; -} - -/****************************************************************************** - * - * set_default_user_mode - * - *****************************************************************************/ -static int set_default_user_mode(struct camera_data *cam) -{ - unsigned char user_mode; - unsigned char frame_rate; - int width = cam->params.roi.width; - int height = cam->params.roi.height; - - switch (cam->params.version.sensor_flags) { - case CPIA2_VP_SENSOR_FLAGS_404: - case CPIA2_VP_SENSOR_FLAGS_407: - case CPIA2_VP_SENSOR_FLAGS_409: - case CPIA2_VP_SENSOR_FLAGS_410: - if ((width > STV_IMAGE_QCIF_COLS) - || (height > STV_IMAGE_QCIF_ROWS)) { - user_mode = CPIA2_VP_USER_MODE_CIF; - } else { - user_mode = CPIA2_VP_USER_MODE_QCIFDS; - } - frame_rate = CPIA2_VP_FRAMERATE_30; - break; - case CPIA2_VP_SENSOR_FLAGS_500: - if ((width > STV_IMAGE_CIF_COLS) - || (height > STV_IMAGE_CIF_ROWS)) { - user_mode = CPIA2_VP_USER_MODE_VGA; - } else { - user_mode = CPIA2_VP_USER_MODE_QVGADS; - } - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - frame_rate = CPIA2_VP_FRAMERATE_15; - else - frame_rate = CPIA2_VP_FRAMERATE_30; - break; - default: - LOG("%s: Invalid sensor flag value 0x%0X\n",__func__, - cam->params.version.sensor_flags); - return -EINVAL; - } - - DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n", - cam->params.version.sensor_flags, user_mode, frame_rate); - cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE, - user_mode); - if(cam->params.vp_params.frame_rate > 0 && - frame_rate > cam->params.vp_params.frame_rate) - frame_rate = cam->params.vp_params.frame_rate; - - cpia2_set_fps(cam, frame_rate); - -// if (cam->params.pnp_id.device_type == DEVICE_STV_676) -// cpia2_do_command(cam, -// CPIA2_CMD_SET_VP_SYSTEM_CTRL, -// TRANSFER_WRITE, -// CPIA2_VP_SYSTEMCTRL_HK_CONTROL | -// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL); - - return 0; -} - -/****************************************************************************** - * - * cpia2_match_video_size - * - * return the best match, where 'best' is as always - * the largest that is not bigger than what is requested. - *****************************************************************************/ -int cpia2_match_video_size(int width, int height) -{ - if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS) - return VIDEOSIZE_VGA; - - if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS) - return VIDEOSIZE_CIF; - - if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS) - return VIDEOSIZE_QVGA; - - if (width >= 288 && height >= 216) - return VIDEOSIZE_288_216; - - if (width >= 256 && height >= 192) - return VIDEOSIZE_256_192; - - if (width >= 224 && height >= 168) - return VIDEOSIZE_224_168; - - if (width >= 192 && height >= 144) - return VIDEOSIZE_192_144; - - if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS) - return VIDEOSIZE_QCIF; - - return -1; -} - -/****************************************************************************** - * - * SetVideoSize - * - *****************************************************************************/ -static int set_vw_size(struct camera_data *cam, int size) -{ - int retval = 0; - - cam->params.vp_params.video_size = size; - - switch (size) { - case VIDEOSIZE_VGA: - DBG("Setting size to VGA\n"); - cam->params.roi.width = STV_IMAGE_VGA_COLS; - cam->params.roi.height = STV_IMAGE_VGA_ROWS; - cam->width = STV_IMAGE_VGA_COLS; - cam->height = STV_IMAGE_VGA_ROWS; - break; - case VIDEOSIZE_CIF: - DBG("Setting size to CIF\n"); - cam->params.roi.width = STV_IMAGE_CIF_COLS; - cam->params.roi.height = STV_IMAGE_CIF_ROWS; - cam->width = STV_IMAGE_CIF_COLS; - cam->height = STV_IMAGE_CIF_ROWS; - break; - case VIDEOSIZE_QVGA: - DBG("Setting size to QVGA\n"); - cam->params.roi.width = STV_IMAGE_QVGA_COLS; - cam->params.roi.height = STV_IMAGE_QVGA_ROWS; - cam->width = STV_IMAGE_QVGA_COLS; - cam->height = STV_IMAGE_QVGA_ROWS; - break; - case VIDEOSIZE_288_216: - cam->params.roi.width = 288; - cam->params.roi.height = 216; - cam->width = 288; - cam->height = 216; - break; - case VIDEOSIZE_256_192: - cam->width = 256; - cam->height = 192; - cam->params.roi.width = 256; - cam->params.roi.height = 192; - break; - case VIDEOSIZE_224_168: - cam->width = 224; - cam->height = 168; - cam->params.roi.width = 224; - cam->params.roi.height = 168; - break; - case VIDEOSIZE_192_144: - cam->width = 192; - cam->height = 144; - cam->params.roi.width = 192; - cam->params.roi.height = 144; - break; - case VIDEOSIZE_QCIF: - DBG("Setting size to QCIF\n"); - cam->params.roi.width = STV_IMAGE_QCIF_COLS; - cam->params.roi.height = STV_IMAGE_QCIF_ROWS; - cam->width = STV_IMAGE_QCIF_COLS; - cam->height = STV_IMAGE_QCIF_ROWS; - break; - default: - retval = -EINVAL; - } - return retval; -} - -/****************************************************************************** - * - * configure_sensor - * - *****************************************************************************/ -static int configure_sensor(struct camera_data *cam, - int req_width, int req_height) -{ - int retval; - - switch (cam->params.version.sensor_flags) { - case CPIA2_VP_SENSOR_FLAGS_404: - case CPIA2_VP_SENSOR_FLAGS_407: - case CPIA2_VP_SENSOR_FLAGS_409: - case CPIA2_VP_SENSOR_FLAGS_410: - retval = config_sensor_410(cam, req_width, req_height); - break; - case CPIA2_VP_SENSOR_FLAGS_500: - retval = config_sensor_500(cam, req_width, req_height); - break; - default: - return -EINVAL; - } - - return retval; -} - -/****************************************************************************** - * - * config_sensor_410 - * - *****************************************************************************/ -static int config_sensor_410(struct camera_data *cam, - int req_width, int req_height) -{ - struct cpia2_command cmd; - int i = 0; - int image_size; - int image_type; - int width = req_width; - int height = req_height; - - /*** - * Make sure size doesn't exceed CIF. - ***/ - if (width > STV_IMAGE_CIF_COLS) - width = STV_IMAGE_CIF_COLS; - if (height > STV_IMAGE_CIF_ROWS) - height = STV_IMAGE_CIF_ROWS; - - image_size = cpia2_match_video_size(width, height); - - DBG("Config 410: width = %d, height = %d\n", width, height); - DBG("Image size returned is %d\n", image_size); - if (image_size >= 0) { - set_vw_size(cam, image_size); - width = cam->params.roi.width; - height = cam->params.roi.height; - - DBG("After set_vw_size(), width = %d, height = %d\n", - width, height); - if (width <= 176 && height <= 144) { - DBG("image type = VIDEOSIZE_QCIF\n"); - image_type = VIDEOSIZE_QCIF; - } - else if (width <= 320 && height <= 240) { - DBG("image type = VIDEOSIZE_QVGA\n"); - image_type = VIDEOSIZE_QVGA; - } - else { - DBG("image type = VIDEOSIZE_CIF\n"); - image_type = VIDEOSIZE_CIF; - } - } else { - ERR("ConfigSensor410 failed\n"); - return -EINVAL; - } - - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.direction = TRANSFER_WRITE; - - /* VC Format */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; - if (image_type == VIDEOSIZE_CIF) { - cmd.buffer.registers[i++].value = - (u8) (CPIA2_VC_VC_FORMAT_UFIRST | - CPIA2_VC_VC_FORMAT_SHORTLINE); - } else { - cmd.buffer.registers[i++].value = - (u8) CPIA2_VC_VC_FORMAT_UFIRST; - } - - /* VC Clocks */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; - if (image_type == VIDEOSIZE_QCIF) { - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - cmd.buffer.registers[i++].value= - (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_672_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV2); - DBG("VC_Clocks (0xc4) should be B\n"); - } - else { - cmd.buffer.registers[i++].value= - (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_CLOCKS_LOGDIV2); - } - } else { - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - cmd.buffer.registers[i++].value = - (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_CLOCKS_LOGDIV0); - } - else { - cmd.buffer.registers[i++].value = - (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | - CPIA2_VC_VC_676_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV0); - } - } - DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value); - - /* Input reqWidth from VC */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = - (u8) (STV_IMAGE_QCIF_COLS / 4); - else - cmd.buffer.registers[i++].value = - (u8) (STV_IMAGE_CIF_COLS / 4); - - /* Timings */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 208; - else - cmd.buffer.registers[i++].value = (u8) 160; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 160; - else - cmd.buffer.registers[i++].value = (u8) 64; - - /* Output Image Size */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; - cmd.buffer.registers[i++].value = cam->params.roi.width / 4; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; - cmd.buffer.registers[i++].value = cam->params.roi.height / 4; - - /* Cropping */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); - else - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); - else - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); - - /* Scaling registers (defaults) */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; - cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; - cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ - - cmd.reg_count = i; - - cpia2_send_command(cam, &cmd); - - return i; -} - - -/****************************************************************************** - * - * config_sensor_500(cam) - * - *****************************************************************************/ -static int config_sensor_500(struct camera_data *cam, - int req_width, int req_height) -{ - struct cpia2_command cmd; - int i = 0; - int image_size = VIDEOSIZE_CIF; - int image_type = VIDEOSIZE_VGA; - int width = req_width; - int height = req_height; - unsigned int device = cam->params.pnp_id.device_type; - - image_size = cpia2_match_video_size(width, height); - - if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS) - image_type = VIDEOSIZE_VGA; - else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS) - image_type = VIDEOSIZE_CIF; - else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS) - image_type = VIDEOSIZE_QVGA; - else - image_type = VIDEOSIZE_QCIF; - - if (image_size >= 0) { - set_vw_size(cam, image_size); - width = cam->params.roi.width; - height = cam->params.roi.height; - } else { - ERR("ConfigSensor500 failed\n"); - return -EINVAL; - } - - DBG("image_size = %d, width = %d, height = %d, type = %d\n", - image_size, width, height, image_type); - - cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; - cmd.direction = TRANSFER_WRITE; - i = 0; - - /* VC Format */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; - cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING; - i++; - - /* VC Clocks */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; - if (device == DEVICE_STV_672) { - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i].value = - (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1; - else - cmd.buffer.registers[i].value = - (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV3); - } else { - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i].value = - (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0; - else - cmd.buffer.registers[i].value = - (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING | - CPIA2_VC_VC_CLOCKS_LOGDIV2); - } - i++; - - DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value); - - /* Input width from VP */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i].value = - (u8) (STV_IMAGE_VGA_COLS / 4); - else - cmd.buffer.registers[i].value = - (u8) (STV_IMAGE_QVGA_COLS / 4); - i++; - DBG("Input width = %d\n", cmd.buffer.registers[i-1].value); - - /* Timings */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 2; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 250; - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = (u8) 125; - else - cmd.buffer.registers[i++].value = (u8) 160; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 2; - else - cmd.buffer.registers[i++].value = (u8) 1; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = (u8) 12; - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = (u8) 64; - else - cmd.buffer.registers[i++].value = (u8) 6; - - /* Output Image Size */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4; - else - cmd.buffer.registers[i++].value = width / 4; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; - if (image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4; - else - cmd.buffer.registers[i++].value = height / 4; - - /* Cropping */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2); - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2); - else if (image_type == VIDEOSIZE_CIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); - else /*if (image_type == VIDEOSIZE_QCIF)*/ - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; - if (image_type == VIDEOSIZE_VGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2); - else if (image_type == VIDEOSIZE_QVGA) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2); - else if (image_type == VIDEOSIZE_CIF) - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); - else /*if (image_type == VIDEOSIZE_QCIF)*/ - cmd.buffer.registers[i++].value = - (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); - - /* Scaling registers (defaults) */ - cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 36; - else - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 32; - else - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 26; - else - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 21; - else - cmd.buffer.registers[i++].value = (u8) 31; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; - cmd.buffer.registers[i++].value = (u8) 0; - - cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */ - else - cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ - - cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; - if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) - cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */ - else - cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ - - cmd.reg_count = i; - - cpia2_send_command(cam, &cmd); - - return i; -} - - -/****************************************************************************** - * - * setallproperties - * - * This sets all user changeable properties to the values in cam->params. - *****************************************************************************/ -static int set_all_properties(struct camera_data *cam) -{ - /** - * Don't set target_kb here, it will be set later. - * framerate and user_mode were already set (set_default_user_mode). - **/ - - cpia2_usb_change_streaming_alternate(cam, - cam->params.camera_state.stream_mode); - - cpia2_do_command(cam, - CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - TRANSFER_WRITE, cam->params.vp_params.gpio_direction); - cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE, - cam->params.vp_params.gpio_data); - - v4l2_ctrl_handler_setup(&cam->hdl); - - wake_system(cam); - - set_lowlight_boost(cam); - - return 0; -} - -/****************************************************************************** - * - * cpia2_save_camera_state - * - *****************************************************************************/ -void cpia2_save_camera_state(struct camera_data *cam) -{ - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); - cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ, - 0); - cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0); - /* Don't get framerate or target_kb. Trust the values we already have */ -} - - -/****************************************************************************** - * - * cpia2_set_flicker_mode - * - *****************************************************************************/ -int cpia2_set_flicker_mode(struct camera_data *cam, int mode) -{ - unsigned char cam_reg; - int err = 0; - - if(cam->params.pnp_id.device_type != DEVICE_STV_672) - return -EINVAL; - - /* Set the appropriate bits in FLICKER_MODES, preserving the rest */ - if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, - TRANSFER_READ, 0))) - return err; - cam_reg = cam->params.flicker_control.cam_register; - - switch(mode) { - case NEVER_FLICKER: - cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; - cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; - break; - case FLICKER_60: - cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; - cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; - break; - case FLICKER_50: - cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; - cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ; - break; - default: - return -EINVAL; - } - - if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES, - TRANSFER_WRITE, cam_reg))) - return err; - - /* Set the appropriate bits in EXP_MODES, preserving the rest */ - if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES, - TRANSFER_READ, 0))) - return err; - cam_reg = cam->params.vp_params.exposure_modes; - - if (mode == NEVER_FLICKER) { - cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; - } else { - cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; - } - - if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES, - TRANSFER_WRITE, cam_reg))) - return err; - - if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, - TRANSFER_WRITE, 1))) - return err; - - switch(mode) { - case NEVER_FLICKER: - case FLICKER_60: - case FLICKER_50: - cam->params.flicker_control.flicker_mode_req = mode; - break; - default: - err = -EINVAL; - } - - return err; -} - -/****************************************************************************** - * - * cpia2_set_property_flip - * - *****************************************************************************/ -void cpia2_set_property_flip(struct camera_data *cam, int prop_val) -{ - unsigned char cam_reg; - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); - cam_reg = cam->params.vp_params.user_effects; - - if (prop_val) - { - cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP; - } - else - { - cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP; - } - cam->params.vp_params.user_effects = cam_reg; - cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, - cam_reg); -} - -/****************************************************************************** - * - * cpia2_set_property_mirror - * - *****************************************************************************/ -void cpia2_set_property_mirror(struct camera_data *cam, int prop_val) -{ - unsigned char cam_reg; - - cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); - cam_reg = cam->params.vp_params.user_effects; - - if (prop_val) - { - cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR; - } - else - { - cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR; - } - cam->params.vp_params.user_effects = cam_reg; - cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, - cam_reg); -} - -/****************************************************************************** - * - * cpia2_set_gpio - * - *****************************************************************************/ -int cpia2_set_gpio(struct camera_data *cam, unsigned char setting) -{ - int ret; - - /* Set the microport direction (register 0x90, should be defined - * already) to 1 (user output), and set the microport data (0x91) to - * the value in the ioctl argument. - */ - - ret = cpia2_do_command(cam, - CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - CPIA2_VC_MP_DIR_OUTPUT, - 255); - if (ret < 0) - return ret; - cam->params.vp_params.gpio_direction = 255; - - ret = cpia2_do_command(cam, - CPIA2_CMD_SET_VC_MP_GPIO_DATA, - CPIA2_VC_MP_DIR_OUTPUT, - setting); - if (ret < 0) - return ret; - cam->params.vp_params.gpio_data = setting; - - return 0; -} - -/****************************************************************************** - * - * cpia2_set_fps - * - *****************************************************************************/ -int cpia2_set_fps(struct camera_data *cam, int framerate) -{ - int retval; - - switch(framerate) { - case CPIA2_VP_FRAMERATE_30: - case CPIA2_VP_FRAMERATE_25: - if(cam->params.pnp_id.device_type == DEVICE_STV_672 && - cam->params.version.sensor_flags == - CPIA2_VP_SENSOR_FLAGS_500) { - return -EINVAL; - } - fallthrough; - case CPIA2_VP_FRAMERATE_15: - case CPIA2_VP_FRAMERATE_12_5: - case CPIA2_VP_FRAMERATE_7_5: - case CPIA2_VP_FRAMERATE_6_25: - break; - default: - return -EINVAL; - } - - if (cam->params.pnp_id.device_type == DEVICE_STV_672 && - framerate == CPIA2_VP_FRAMERATE_15) - framerate = 0; /* Work around bug in VP4 */ - - retval = cpia2_do_command(cam, - CPIA2_CMD_FRAMERATE_REQ, - TRANSFER_WRITE, - framerate); - - if(retval == 0) - cam->params.vp_params.frame_rate = framerate; - - return retval; -} - -/****************************************************************************** - * - * cpia2_set_brightness - * - *****************************************************************************/ -void cpia2_set_brightness(struct camera_data *cam, unsigned char value) -{ - /*** - * Don't let the register be set to zero - bug in VP4 - flash of full - * brightness - ***/ - if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0) - value++; - DBG("Setting brightness to %d (0x%0x)\n", value, value); - cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value); -} - -/****************************************************************************** - * - * cpia2_set_contrast - * - *****************************************************************************/ -void cpia2_set_contrast(struct camera_data *cam, unsigned char value) -{ - DBG("Setting contrast to %d (0x%0x)\n", value, value); - cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value); -} - -/****************************************************************************** - * - * cpia2_set_saturation - * - *****************************************************************************/ -void cpia2_set_saturation(struct camera_data *cam, unsigned char value) -{ - DBG("Setting saturation to %d (0x%0x)\n", value, value); - cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value); -} - -/****************************************************************************** - * - * wake_system - * - *****************************************************************************/ -static void wake_system(struct camera_data *cam) -{ - cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0); -} - -/****************************************************************************** - * - * set_lowlight_boost - * - * Valid for STV500 sensor only - *****************************************************************************/ -static void set_lowlight_boost(struct camera_data *cam) -{ - struct cpia2_command cmd; - - if (cam->params.pnp_id.device_type != DEVICE_STV_672 || - cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500) - return; - - cmd.direction = TRANSFER_WRITE; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 3; - cmd.start = CPIA2_VP_RAM_ADDR_H; - - cmd.buffer.block_data[0] = 0; /* High byte of address to write to */ - cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */ - cmd.buffer.block_data[2] = 0; /* High byte of data to write */ - - cpia2_send_command(cam, &cmd); - - if (cam->params.vp_params.lowlight_boost) { - cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */ - } else { - cmd.buffer.block_data[0] = 0x06; - } - cmd.start = CPIA2_VP_RAM_DATA; - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - - /* Rehash the VP4 values */ - cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1); -} - -/****************************************************************************** - * - * cpia2_set_format - * - * Assumes that new size is already set in param struct. - *****************************************************************************/ -void cpia2_set_format(struct camera_data *cam) -{ - cam->flush = true; - - cpia2_usb_stream_pause(cam); - - /* reset camera to new size */ - cpia2_set_low_power(cam); - cpia2_reset_camera(cam); - cam->flush = false; - - cpia2_dbg_dump_registers(cam); - - cpia2_usb_stream_resume(cam); -} - -/****************************************************************************** - * - * cpia2_dbg_dump_registers - * - *****************************************************************************/ -void cpia2_dbg_dump_registers(struct camera_data *cam) -{ -#ifdef _CPIA2_DEBUG_ - struct cpia2_command cmd; - - if (!(debugs_on & DEBUG_DUMP_REGS)) - return; - - cmd.direction = TRANSFER_READ; - - /* Start with bank 0 (SYSTEM) */ - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; - cmd.reg_count = 3; - cmd.start = 0; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "System Device Hi = 0x%X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "System Device Lo = 0x%X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "System_system control = 0x%X\n", - cmd.buffer.block_data[2]); - - /* Bank 1 (VC) */ - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.reg_count = 4; - cmd.start = 0x80; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "ASIC_ID = 0x%X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "ASIC_REV = 0x%X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "PW_CONTRL = 0x%X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "WAKEUP = 0x%X\n", - cmd.buffer.block_data[3]); - - cmd.start = 0xA0; /* ST_CTRL */ - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "Stream ctrl = 0x%X\n", - cmd.buffer.block_data[0]); - - cmd.start = 0xA4; /* Stream status */ - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "Stream status = 0x%X\n", - cmd.buffer.block_data[0]); - - cmd.start = 0xA8; /* USB status */ - cmd.reg_count = 3; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "USB_CTRL = 0x%X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "USB_STRM = 0x%X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "USB_STATUS = 0x%X\n", - cmd.buffer.block_data[2]); - - cmd.start = 0xAF; /* USB settings */ - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "USB settings = 0x%X\n", - cmd.buffer.block_data[0]); - - cmd.start = 0xC0; /* VC stuff */ - cmd.reg_count = 26; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VC Control = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VC Format = 0x%0X\n", - cmd.buffer.block_data[3]); - printk(KERN_DEBUG "VC Clocks = 0x%0X\n", - cmd.buffer.block_data[4]); - printk(KERN_DEBUG "VC IHSize = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n", - cmd.buffer.block_data[7]); - printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n", - cmd.buffer.block_data[8]); - printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n", - cmd.buffer.block_data[9]); - printk(KERN_DEBUG "VC OHSize = 0x%0X\n", - cmd.buffer.block_data[10]); - printk(KERN_DEBUG "VC OVSize = 0x%0X\n", - cmd.buffer.block_data[11]); - printk(KERN_DEBUG "VC HCrop = 0x%0X\n", - cmd.buffer.block_data[12]); - printk(KERN_DEBUG "VC VCrop = 0x%0X\n", - cmd.buffer.block_data[13]); - printk(KERN_DEBUG "VC HPhase = 0x%0X\n", - cmd.buffer.block_data[14]); - printk(KERN_DEBUG "VC VPhase = 0x%0X\n", - cmd.buffer.block_data[15]); - printk(KERN_DEBUG "VC HIspan = 0x%0X\n", - cmd.buffer.block_data[16]); - printk(KERN_DEBUG "VC VIspan = 0x%0X\n", - cmd.buffer.block_data[17]); - printk(KERN_DEBUG "VC HiCrop = 0x%0X\n", - cmd.buffer.block_data[18]); - printk(KERN_DEBUG "VC ViCrop = 0x%0X\n", - cmd.buffer.block_data[19]); - printk(KERN_DEBUG "VC HiFract = 0x%0X\n", - cmd.buffer.block_data[20]); - printk(KERN_DEBUG "VC ViFract = 0x%0X\n", - cmd.buffer.block_data[21]); - printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n", - cmd.buffer.block_data[22]); - printk(KERN_DEBUG "VC Creep Per = 0x%0X\n", - cmd.buffer.block_data[23]); - printk(KERN_DEBUG "VC User Sq. = 0x%0X\n", - cmd.buffer.block_data[24]); - printk(KERN_DEBUG "VC Target KB = 0x%0X\n", - cmd.buffer.block_data[25]); - - /*** VP ***/ - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; - cmd.reg_count = 14; - cmd.start = 0; - cpia2_send_command(cam, &cmd); - - printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP Sys State = 0x%0X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n", - cmd.buffer.block_data[3]); - printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VP Dev Config = 0x%0X\n", - cmd.buffer.block_data[7]); - printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n", - cmd.buffer.block_data[8]); - printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n", - cmd.buffer.block_data[9]); - printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n", - cmd.buffer.block_data[10]); - printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n", - cmd.buffer.block_data[11]); - printk(KERN_DEBUG "VP RAM Data = 0x%0X\n", - cmd.buffer.block_data[12]); - printk(KERN_DEBUG "Do Call = 0x%0X\n", - cmd.buffer.block_data[13]); - - if (cam->params.pnp_id.device_type == DEVICE_STV_672) { - cmd.reg_count = 9; - cmd.start = 0x0E; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "VP Framerate = 0x%0X\n", - cmd.buffer.block_data[3]); - printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", - cmd.buffer.block_data[4]); - printk(KERN_DEBUG "VP White Bal = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VP WB thresh = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n", - cmd.buffer.block_data[7]); - printk(KERN_DEBUG "VP Exp Target = 0x%0X\n", - cmd.buffer.block_data[8]); - - cmd.reg_count = 1; - cmd.start = 0x1B; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n", - cmd.buffer.block_data[0]); - } else { - cmd.reg_count = 8 ; - cmd.start = 0x0E; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", - cmd.buffer.block_data[5]); - printk(KERN_DEBUG "VP Framerate = 0x%0X\n", - cmd.buffer.block_data[6]); - printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", - cmd.buffer.block_data[7]); - - cmd.reg_count = 1; - cmd.start = CPIA2_VP5_EXPOSURE_TARGET; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n", - cmd.buffer.block_data[0]); - - cmd.reg_count = 4; - cmd.start = 0x3A; - cpia2_send_command(cam, &cmd); - printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n", - cmd.buffer.block_data[0]); - printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n", - cmd.buffer.block_data[1]); - printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n", - cmd.buffer.block_data[2]); - printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n", - cmd.buffer.block_data[3]); - } -#endif -} - -/****************************************************************************** - * - * reset_camera_struct - * - * Sets all values to the defaults - *****************************************************************************/ -static void reset_camera_struct(struct camera_data *cam) -{ - /*** - * The following parameter values are the defaults from the register map. - ***/ - cam->params.vp_params.lowlight_boost = 0; - - /* FlickerModes */ - cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER; - - /* jpeg params */ - cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT; - cam->params.compression.creep_period = 2; - cam->params.compression.user_squeeze = 20; - cam->params.compression.inhibit_htables = false; - - /* gpio params */ - cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */ - cam->params.vp_params.gpio_data = 0; - - /* Target kb params */ - cam->params.vc_params.quality = 100; - - /*** - * Set Sensor FPS as fast as possible. - ***/ - if(cam->params.pnp_id.device_type == DEVICE_STV_672) { - if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) - cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15; - else - cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; - } else { - cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; - } - - /*** - * Set default video mode as large as possible : - * for vga sensor set to vga, for cif sensor set to CIF. - ***/ - if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) { - cam->sensor_type = CPIA2_SENSOR_500; - cam->video_size = VIDEOSIZE_VGA; - cam->params.roi.width = STV_IMAGE_VGA_COLS; - cam->params.roi.height = STV_IMAGE_VGA_ROWS; - } else { - cam->sensor_type = CPIA2_SENSOR_410; - cam->video_size = VIDEOSIZE_CIF; - cam->params.roi.width = STV_IMAGE_CIF_COLS; - cam->params.roi.height = STV_IMAGE_CIF_ROWS; - } - - cam->width = cam->params.roi.width; - cam->height = cam->params.roi.height; -} - -/****************************************************************************** - * - * cpia2_init_camera_struct - * - * Deinitialize camera struct - *****************************************************************************/ -void cpia2_deinit_camera_struct(struct camera_data *cam, struct usb_interface *intf) -{ - v4l2_device_unregister(&cam->v4l2_dev); - kfree(cam); -} - -/****************************************************************************** - * - * cpia2_init_camera_struct - * - * Initializes camera struct, does not call reset to fill in defaults. - *****************************************************************************/ -struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf) -{ - struct camera_data *cam; - - cam = kzalloc(sizeof(*cam), GFP_KERNEL); - - if (!cam) { - ERR("couldn't kmalloc cpia2 struct\n"); - return NULL; - } - - cam->v4l2_dev.release = cpia2_camera_release; - if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) { - v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n"); - kfree(cam); - return NULL; - } - - mutex_init(&cam->v4l2_lock); - init_waitqueue_head(&cam->wq_stream); - - return cam; -} - -/****************************************************************************** - * - * cpia2_init_camera - * - * Initializes camera. - *****************************************************************************/ -int cpia2_init_camera(struct camera_data *cam) -{ - DBG("Start\n"); - - cam->mmapped = false; - - /* Get sensor and asic types before reset. */ - cpia2_set_high_power(cam); - cpia2_get_version_info(cam); - if (cam->params.version.asic_id != CPIA2_ASIC_672) { - ERR("Device IO error (asicID has incorrect value of 0x%X\n", - cam->params.version.asic_id); - return -ENODEV; - } - - /* Set GPIO direction and data to a safe state. */ - cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, - TRANSFER_WRITE, 0); - cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, - TRANSFER_WRITE, 0); - - /* resetting struct requires version info for sensor and asic types */ - reset_camera_struct(cam); - - cpia2_set_low_power(cam); - - DBG("End\n"); - - return 0; -} - -/****************************************************************************** - * - * cpia2_allocate_buffers - * - *****************************************************************************/ -int cpia2_allocate_buffers(struct camera_data *cam) -{ - int i; - - if(!cam->buffers) { - u32 size = cam->num_frames*sizeof(struct framebuf); - cam->buffers = kmalloc(size, GFP_KERNEL); - if(!cam->buffers) { - ERR("couldn't kmalloc frame buffer structures\n"); - return -ENOMEM; - } - } - - if(!cam->frame_buffer) { - cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames); - if (!cam->frame_buffer) { - ERR("couldn't vmalloc frame buffer data area\n"); - kfree(cam->buffers); - cam->buffers = NULL; - return -ENOMEM; - } - } - - for(i=0; i<cam->num_frames-1; ++i) { - cam->buffers[i].next = &cam->buffers[i+1]; - cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; - cam->buffers[i].status = FRAME_EMPTY; - cam->buffers[i].length = 0; - cam->buffers[i].max_length = 0; - cam->buffers[i].num = i; - } - cam->buffers[i].next = cam->buffers; - cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; - cam->buffers[i].status = FRAME_EMPTY; - cam->buffers[i].length = 0; - cam->buffers[i].max_length = 0; - cam->buffers[i].num = i; - cam->curbuff = cam->buffers; - cam->workbuff = cam->curbuff->next; - DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff, - cam->workbuff); - return 0; -} - -/****************************************************************************** - * - * cpia2_free_buffers - * - *****************************************************************************/ -void cpia2_free_buffers(struct camera_data *cam) -{ - if(cam->buffers) { - kfree(cam->buffers); - cam->buffers = NULL; - } - if(cam->frame_buffer) { - rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames); - cam->frame_buffer = NULL; - } -} - -/****************************************************************************** - * - * cpia2_read - * - *****************************************************************************/ -long cpia2_read(struct camera_data *cam, - char __user *buf, unsigned long count, int noblock) -{ - struct framebuf *frame; - - if (!count) - return 0; - - if (!buf) { - ERR("%s: buffer NULL\n",__func__); - return -EINVAL; - } - - if (!cam) { - ERR("%s: Internal error, camera_data NULL!\n",__func__); - return -EINVAL; - } - - if (!cam->streaming) { - /* Start streaming */ - cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - } - - /* Copy cam->curbuff in case it changes while we're processing */ - frame = cam->curbuff; - if (noblock && frame->status != FRAME_READY) { - return -EAGAIN; - } - - if (frame->status != FRAME_READY) { - mutex_unlock(&cam->v4l2_lock); - wait_event_interruptible(cam->wq_stream, - !video_is_registered(&cam->vdev) || - (frame = cam->curbuff)->status == FRAME_READY); - mutex_lock(&cam->v4l2_lock); - if (signal_pending(current)) - return -ERESTARTSYS; - if (!video_is_registered(&cam->vdev)) - return 0; - } - - /* copy data to user space */ - if (frame->length > count) - return -EFAULT; - if (copy_to_user(buf, frame->data, frame->length)) - return -EFAULT; - - count = frame->length; - - frame->status = FRAME_EMPTY; - - return count; -} - -/****************************************************************************** - * - * cpia2_poll - * - *****************************************************************************/ -__poll_t cpia2_poll(struct camera_data *cam, struct file *filp, - poll_table *wait) -{ - __poll_t status = v4l2_ctrl_poll(filp, wait); - - if ((poll_requested_events(wait) & (EPOLLIN | EPOLLRDNORM)) && - !cam->streaming) { - /* Start streaming */ - cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - } - - poll_wait(filp, &cam->wq_stream, wait); - - if (cam->curbuff->status == FRAME_READY) - status |= EPOLLIN | EPOLLRDNORM; - - return status; -} - -/****************************************************************************** - * - * cpia2_remap_buffer - * - *****************************************************************************/ -int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma) -{ - const char *adr = (const char *)vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long start = (unsigned long) adr; - unsigned long page, pos; - - DBG("mmap offset:%ld size:%ld\n", start_offset, size); - - if (!video_is_registered(&cam->vdev)) - return -ENODEV; - - if (size > cam->frame_size*cam->num_frames || - (start_offset % cam->frame_size) != 0 || - (start_offset+size > cam->frame_size*cam->num_frames)) - return -EINVAL; - - pos = ((unsigned long) (cam->frame_buffer)) + start_offset; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - cam->mmapped = true; - return 0; -} diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_registers.h b/drivers/staging/media/deprecated/cpia2/cpia2_registers.h deleted file mode 100644 index 8c73812a15c9..000000000000 --- a/drivers/staging/media/deprecated/cpia2/cpia2_registers.h +++ /dev/null @@ -1,463 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/**************************************************************************** - * - * Filename: cpia2registers.h - * - * Copyright 2001, STMicrolectronics, Inc. - * - * Description: - * Definitions for the CPia2 register set - * - ****************************************************************************/ - -#ifndef CPIA2_REGISTER_HEADER -#define CPIA2_REGISTER_HEADER - -/*** - * System register set (Bank 0) - ***/ -#define CPIA2_SYSTEM_DEVICE_HI 0x00 -#define CPIA2_SYSTEM_DEVICE_LO 0x01 - -#define CPIA2_SYSTEM_SYSTEM_CONTROL 0x02 -#define CPIA2_SYSTEM_CONTROL_LOW_POWER 0x00 -#define CPIA2_SYSTEM_CONTROL_HIGH_POWER 0x01 -#define CPIA2_SYSTEM_CONTROL_SUSPEND 0x02 -#define CPIA2_SYSTEM_CONTROL_V2W_ERR 0x10 -#define CPIA2_SYSTEM_CONTROL_RB_ERR 0x10 -#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR 0x80 - -#define CPIA2_SYSTEM_INT_PACKET_CTRL 0x04 -#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01 -#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF 0x02 -#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1 0x04 - -#define CPIA2_SYSTEM_CACHE_CTRL 0x05 -#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET 0x01 -#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH 0x02 - -#define CPIA2_SYSTEM_SERIAL_CTRL 0x06 -#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD 0x00 -#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD 0x01 -#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD 0x02 -#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD 0x03 -#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD 0x04 -#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD 0x05 - -#define CPIA2_SYSTEM_SERIAL_DATA 0x07 - -#define CPIA2_SYSTEM_VP_SERIAL_ADDR 0x08 - -/*** - * I2C addresses for various devices in CPiA2 - ***/ -#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR 0x20 -#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP 0x88 -#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP 0x8A - -#define CPIA2_SYSTEM_SPARE_REG1 0x09 -#define CPIA2_SYSTEM_SPARE_REG2 0x0A -#define CPIA2_SYSTEM_SPARE_REG3 0x0B - -#define CPIA2_SYSTEM_MC_PORT_0 0x0C -#define CPIA2_SYSTEM_MC_PORT_1 0x0D -#define CPIA2_SYSTEM_MC_PORT_2 0x0E -#define CPIA2_SYSTEM_MC_PORT_3 0x0F - -#define CPIA2_SYSTEM_STATUS_PKT 0x20 -#define CPIA2_SYSTEM_STATUS_PKT_END 0x27 - -#define CPIA2_SYSTEM_DESCRIP_VID_HI 0x30 -#define CPIA2_SYSTEM_DESCRIP_VID_LO 0x31 -#define CPIA2_SYSTEM_DESCRIP_PID_HI 0x32 -#define CPIA2_SYSTEM_DESCRIP_PID_LO 0x33 - -#define CPIA2_SYSTEM_FW_VERSION_HI 0x34 -#define CPIA2_SYSTEM_FW_VERSION_LO 0x35 - -#define CPIA2_SYSTEM_CACHE_START_INDEX 0x80 -#define CPIA2_SYSTEM_CACHE_MAX_WRITES 0x10 - -/*** - * VC register set (Bank 1) - ***/ -#define CPIA2_VC_ASIC_ID 0x80 - -#define CPIA2_VC_ASIC_REV 0x81 - -#define CPIA2_VC_PW_CTRL 0x82 -#define CPIA2_VC_PW_CTRL_COLDSTART 0x01 -#define CPIA2_VC_PW_CTRL_CP_CLK_EN 0x02 -#define CPIA2_VC_PW_CTRL_VP_RESET_N 0x04 -#define CPIA2_VC_PW_CTRL_VC_CLK_EN 0x08 -#define CPIA2_VC_PW_CTRL_VC_RESET_N 0x10 -#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND 0x20 -#define CPIA2_VC_PW_CTRL_UDC_SUSPEND 0x40 -#define CPIA2_VC_PW_CTRL_PWR_DOWN 0x80 - -#define CPIA2_VC_WAKEUP 0x83 -#define CPIA2_VC_WAKEUP_SW_ENABLE 0x01 -#define CPIA2_VC_WAKEUP_XX_ENABLE 0x02 -#define CPIA2_VC_WAKEUP_SW_ATWAKEUP 0x04 -#define CPIA2_VC_WAKEUP_XX_ATWAKEUP 0x08 - -#define CPIA2_VC_CLOCK_CTRL 0x84 -#define CPIA2_VC_CLOCK_CTRL_TESTUP72 0x01 - -#define CPIA2_VC_INT_ENABLE 0x88 -#define CPIA2_VC_INT_ENABLE_XX_IE 0x01 -#define CPIA2_VC_INT_ENABLE_SW_IE 0x02 -#define CPIA2_VC_INT_ENABLE_VC_IE 0x04 -#define CPIA2_VC_INT_ENABLE_USBDATA_IE 0x08 -#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10 -#define CPIA2_VC_INT_ENABLE_USBCFG_IE 0x20 - -#define CPIA2_VC_INT_FLAG 0x89 -#define CPIA2_VC_INT_ENABLE_XX_FLAG 0x01 -#define CPIA2_VC_INT_ENABLE_SW_FLAG 0x02 -#define CPIA2_VC_INT_ENABLE_VC_FLAG 0x04 -#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG 0x08 -#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10 -#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG 0x20 -#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80 - -#define CPIA2_VC_INT_STATE 0x8A -#define CPIA2_VC_INT_STATE_XX_STATE 0x01 -#define CPIA2_VC_INT_STATE_SW_STATE 0x02 - -#define CPIA2_VC_MP_DIR 0x90 -#define CPIA2_VC_MP_DIR_INPUT 0x00 -#define CPIA2_VC_MP_DIR_OUTPUT 0x01 - -#define CPIA2_VC_MP_DATA 0x91 - -#define CPIA2_VC_DP_CTRL 0x98 -#define CPIA2_VC_DP_CTRL_MODE_0 0x00 -#define CPIA2_VC_DP_CTRL_MODE_A 0x01 -#define CPIA2_VC_DP_CTRL_MODE_B 0x02 -#define CPIA2_VC_DP_CTRL_MODE_C 0x03 -#define CPIA2_VC_DP_CTRL_FAKE_FST 0x04 - -#define CPIA2_VC_AD_CTRL 0x99 -#define CPIA2_VC_AD_CTRL_SRC_0 0x00 -#define CPIA2_VC_AD_CTRL_SRC_DIGI_A 0x01 -#define CPIA2_VC_AD_CTRL_SRC_REG 0x02 -#define CPIA2_VC_AD_CTRL_DST_USB 0x00 -#define CPIA2_VC_AD_CTRL_DST_REG 0x04 - -#define CPIA2_VC_AD_TEST_IN 0x9B - -#define CPIA2_VC_AD_TEST_OUT 0x9C - -#define CPIA2_VC_AD_STATUS 0x9D -#define CPIA2_VC_AD_STATUS_EMPTY 0x01 -#define CPIA2_VC_AD_STATUS_FULL 0x02 - -#define CPIA2_VC_DP_DATA 0x9E - -#define CPIA2_VC_ST_CTRL 0xA0 -#define CPIA2_VC_ST_CTRL_SRC_VC 0x00 -#define CPIA2_VC_ST_CTRL_SRC_DP 0x01 -#define CPIA2_VC_ST_CTRL_SRC_REG 0x02 - -#define CPIA2_VC_ST_CTRL_RAW_SELECT 0x04 - -#define CPIA2_VC_ST_CTRL_DST_USB 0x00 -#define CPIA2_VC_ST_CTRL_DST_DP 0x08 -#define CPIA2_VC_ST_CTRL_DST_REG 0x10 - -#define CPIA2_VC_ST_CTRL_FIFO_ENABLE 0x20 -#define CPIA2_VC_ST_CTRL_EOF_DETECT 0x40 - -#define CPIA2_VC_ST_TEST 0xA1 -#define CPIA2_VC_ST_TEST_MODE_MANUAL 0x00 -#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02 - -#define CPIA2_VC_ST_TEST_AUTO_FILL 0x08 - -#define CPIA2_VC_ST_TEST_REPEAT_FIFO 0x10 - -#define CPIA2_VC_ST_TEST_IN 0xA2 - -#define CPIA2_VC_ST_TEST_OUT 0xA3 - -#define CPIA2_VC_ST_STATUS 0xA4 -#define CPIA2_VC_ST_STATUS_EMPTY 0x01 -#define CPIA2_VC_ST_STATUS_FULL 0x02 - -#define CPIA2_VC_ST_FRAME_DETECT_1 0xA5 - -#define CPIA2_VC_ST_FRAME_DETECT_2 0xA6 - -#define CPIA2_VC_USB_CTRL 0xA8 -#define CPIA2_VC_USB_CTRL_CMD_STALLED 0x01 -#define CPIA2_VC_USB_CTRL_CMD_READY 0x02 -#define CPIA2_VC_USB_CTRL_CMD_STATUS 0x04 -#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR 0x08 -#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH 0x10 -#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80 - -#define CPIA2_VC_USB_STRM 0xA9 -#define CPIA2_VC_USB_STRM_ISO_ENABLE 0x01 -#define CPIA2_VC_USB_STRM_BLK_ENABLE 0x02 -#define CPIA2_VC_USB_STRM_INT_ENABLE 0x04 -#define CPIA2_VC_USB_STRM_AUD_ENABLE 0x08 - -#define CPIA2_VC_USB_STATUS 0xAA -#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS 0x01 -#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02 -#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE 0x04 -#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE 0x08 -#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY 0x10 -#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN 0x20 -#define CPIA2_VC_USB_STATUS_CONFIG_DONE 0x40 -#define CPIA2_VC_USB_STATUS_USB_SUSPEND 0x80 - -#define CPIA2_VC_USB_CMDW 0xAB - -#define CPIA2_VC_USB_DATARW 0xAC - -#define CPIA2_VC_USB_INFO 0xAD - -#define CPIA2_VC_USB_CONFIG 0xAE - -#define CPIA2_VC_USB_SETTINGS 0xAF -#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK 0x03 -#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C -#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70 - -#define CPIA2_VC_USB_ISOLIM 0xB0 - -#define CPIA2_VC_USB_ISOFAILS 0xB1 - -#define CPIA2_VC_USB_ISOMAXPKTHI 0xB2 - -#define CPIA2_VC_USB_ISOMAXPKTLO 0xB3 - -#define CPIA2_VC_V2W_CTRL 0xB8 -#define CPIA2_VC_V2W_SELECT 0x01 - -#define CPIA2_VC_V2W_SCL 0xB9 - -#define CPIA2_VC_V2W_SDA 0xBA - -#define CPIA2_VC_VC_CTRL 0xC0 -#define CPIA2_VC_VC_CTRL_RUN 0x01 -#define CPIA2_VC_VC_CTRL_SINGLESHOT 0x02 -#define CPIA2_VC_VC_CTRL_IDLING 0x04 -#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10 -#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20 -#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE 0x40 - -#define CPIA2_VC_VC_RESTART_IVAL_HI 0xC1 - -#define CPIA2_VC_VC_RESTART_IVAL_LO 0xC2 - -#define CPIA2_VC_VC_FORMAT 0xC3 -#define CPIA2_VC_VC_FORMAT_UFIRST 0x01 -#define CPIA2_VC_VC_FORMAT_MONO 0x02 -#define CPIA2_VC_VC_FORMAT_DECIMATING 0x04 -#define CPIA2_VC_VC_FORMAT_SHORTLINE 0x08 -#define CPIA2_VC_VC_FORMAT_SELFTEST 0x10 - -#define CPIA2_VC_VC_CLOCKS 0xC4 -#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK 0x03 -#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 0x04 -#define CPIA2_VC_VC_672_CLOCKS_SCALING 0x08 -#define CPIA2_VC_VC_CLOCKS_LOGDIV0 0x00 -#define CPIA2_VC_VC_CLOCKS_LOGDIV1 0x01 -#define CPIA2_VC_VC_CLOCKS_LOGDIV2 0x02 -#define CPIA2_VC_VC_CLOCKS_LOGDIV3 0x03 -#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 0x08 -#define CPIA2_VC_VC_676_CLOCKS_SCALING 0x10 - -#define CPIA2_VC_VC_IHSIZE_LO 0xC5 - -#define CPIA2_VC_VC_XLIM_HI 0xC6 - -#define CPIA2_VC_VC_XLIM_LO 0xC7 - -#define CPIA2_VC_VC_YLIM_HI 0xC8 - -#define CPIA2_VC_VC_YLIM_LO 0xC9 - -#define CPIA2_VC_VC_OHSIZE 0xCA - -#define CPIA2_VC_VC_OVSIZE 0xCB - -#define CPIA2_VC_VC_HCROP 0xCC - -#define CPIA2_VC_VC_VCROP 0xCD - -#define CPIA2_VC_VC_HPHASE 0xCE - -#define CPIA2_VC_VC_VPHASE 0xCF - -#define CPIA2_VC_VC_HISPAN 0xD0 - -#define CPIA2_VC_VC_VISPAN 0xD1 - -#define CPIA2_VC_VC_HICROP 0xD2 - -#define CPIA2_VC_VC_VICROP 0xD3 - -#define CPIA2_VC_VC_HFRACT 0xD4 -#define CPIA2_VC_VC_HFRACT_DEN_MASK 0x0F -#define CPIA2_VC_VC_HFRACT_NUM_MASK 0xF0 - -#define CPIA2_VC_VC_VFRACT 0xD5 -#define CPIA2_VC_VC_VFRACT_DEN_MASK 0x0F -#define CPIA2_VC_VC_VFRACT_NUM_MASK 0xF0 - -#define CPIA2_VC_VC_JPEG_OPT 0xD6 -#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE 0x01 -#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02 -#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE 0x04 -#define CPIA2_VC_VC_JPEG_OPT_DEFAULT (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\ - CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE) - - -#define CPIA2_VC_VC_CREEP_PERIOD 0xD7 -#define CPIA2_VC_VC_USER_SQUEEZE 0xD8 -#define CPIA2_VC_VC_TARGET_KB 0xD9 - -#define CPIA2_VC_VC_AUTO_SQUEEZE 0xE6 - - -/*** - * VP register set (Bank 2) - ***/ -#define CPIA2_VP_DEVICEH 0 -#define CPIA2_VP_DEVICEL 1 - -#define CPIA2_VP_SYSTEMSTATE 0x02 -#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE 0x01 - -#define CPIA2_VP_SYSTEMCTRL 0x03 -#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR 0x80 -#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL 0x20 -#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE 0x10 -#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP 0x08 -#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD 0x04 -#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL 0x02 -#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL 0x01 - -#define CPIA2_VP_SENSOR_FLAGS 0x05 -#define CPIA2_VP_SENSOR_FLAGS_404 0x01 -#define CPIA2_VP_SENSOR_FLAGS_407 0x02 -#define CPIA2_VP_SENSOR_FLAGS_409 0x04 -#define CPIA2_VP_SENSOR_FLAGS_410 0x08 -#define CPIA2_VP_SENSOR_FLAGS_500 0x10 - -#define CPIA2_VP_SENSOR_REV 0x06 - -#define CPIA2_VP_DEVICE_CONFIG 0x07 -#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE 0x01 - -#define CPIA2_VP_GPIO_DIRECTION 0x08 -#define CPIA2_VP_GPIO_READ 0xFF -#define CPIA2_VP_GPIO_WRITE 0x00 - -#define CPIA2_VP_GPIO_DATA 0x09 - -#define CPIA2_VP_RAM_ADDR_H 0x0A -#define CPIA2_VP_RAM_ADDR_L 0x0B -#define CPIA2_VP_RAM_DATA 0x0C - -#define CPIA2_VP_PATCH_REV 0x0F - -#define CPIA2_VP4_USER_MODE 0x10 -#define CPIA2_VP5_USER_MODE 0x13 -#define CPIA2_VP_USER_MODE_CIF 0x01 -#define CPIA2_VP_USER_MODE_QCIFDS 0x02 -#define CPIA2_VP_USER_MODE_QCIFPTC 0x04 -#define CPIA2_VP_USER_MODE_QVGADS 0x08 -#define CPIA2_VP_USER_MODE_QVGAPTC 0x10 -#define CPIA2_VP_USER_MODE_VGA 0x20 - -#define CPIA2_VP4_FRAMERATE_REQUEST 0x11 -#define CPIA2_VP5_FRAMERATE_REQUEST 0x14 -#define CPIA2_VP_FRAMERATE_60 0x80 -#define CPIA2_VP_FRAMERATE_50 0x40 -#define CPIA2_VP_FRAMERATE_30 0x20 -#define CPIA2_VP_FRAMERATE_25 0x10 -#define CPIA2_VP_FRAMERATE_15 0x08 -#define CPIA2_VP_FRAMERATE_12_5 0x04 -#define CPIA2_VP_FRAMERATE_7_5 0x02 -#define CPIA2_VP_FRAMERATE_6_25 0x01 - -#define CPIA2_VP4_USER_EFFECTS 0x12 -#define CPIA2_VP5_USER_EFFECTS 0x15 -#define CPIA2_VP_USER_EFFECTS_COLBARS 0x01 -#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD 0x02 -#define CPIA2_VP_USER_EFFECTS_MIRROR 0x04 -#define CPIA2_VP_USER_EFFECTS_FLIP 0x40 // VP5 only - -/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User - * Effects */ -#define CPIA2_VP_EXPOSURE_MODES 0x15 -#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER 0x20 -#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP 0x10 - -#define CPIA2_VP4_EXPOSURE_TARGET 0x16 // VP4 -#define CPIA2_VP5_EXPOSURE_TARGET 0x20 // VP5 - -#define CPIA2_VP_FLICKER_MODES 0x1B -#define CPIA2_VP_FLICKER_MODES_50HZ 0x80 -#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ 0x40 -#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER 0x20 -#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB 0x10 -#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ 0x08 -#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ 0x04 - -#define CPIA2_VP_UMISC 0x1D -#define CPIA2_VP_UMISC_FORCE_MONO 0x80 -#define CPIA2_VP_UMISC_FORCE_ID_MASK 0x40 -#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS 0x20 -#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS 0x08 -#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS 0x04 -#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT 0x02 - -#define CPIA2_VP5_ANTIFLKRSETUP 0x22 //34 - -#define CPIA2_VP_INTERPOLATION 0x24 -#define CPIA2_VP_INTERPOLATION_EVEN_FIRST 0x40 -#define CPIA2_VP_INTERPOLATION_HJOG 0x20 -#define CPIA2_VP_INTERPOLATION_VJOG 0x10 - -#define CPIA2_VP_GAMMA 0x25 -#define CPIA2_VP_DEFAULT_GAMMA 0x10 - -#define CPIA2_VP_YRANGE 0x26 - -#define CPIA2_VP_SATURATION 0x27 - -#define CPIA2_VP5_MYBLACK_LEVEL 0x3A //58 -#define CPIA2_VP5_MCYRANGE 0x3B //59 -#define CPIA2_VP5_MYCEILING 0x3C //60 -#define CPIA2_VP5_MCUVSATURATION 0x3D //61 - - -#define CPIA2_VP_REHASH_VALUES 0x60 - - -/*** - * Common sensor registers - ***/ -#define CPIA2_SENSOR_DEVICE_H 0x00 -#define CPIA2_SENSOR_DEVICE_L 0x01 - -#define CPIA2_SENSOR_DATA_FORMAT 0x16 -#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR 0x08 -#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR 0x10 - -#define CPIA2_SENSOR_CR1 0x76 -#define CPIA2_SENSOR_CR1_STAND_BY 0x01 -#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN 0x02 -#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC 0x04 -#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR 0x08 -#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10 -#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP 0x20 -#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP 0x40 - -#endif diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_usb.c b/drivers/staging/media/deprecated/cpia2/cpia2_usb.c deleted file mode 100644 index cba03b286473..000000000000 --- a/drivers/staging/media/deprecated/cpia2/cpia2_usb.c +++ /dev/null @@ -1,966 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/**************************************************************************** - * - * Filename: cpia2_usb.c - * - * Copyright 2001, STMicrolectronics, Inc. - * Contact: steve.miller@st.com - * - * Description: - * This is a USB driver for CPia2 based video cameras. - * The infrastructure of this driver is based on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox <alan@lxorguk.ukuu.org.uk> - ****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/module.h> - -#include "cpia2.h" - -static int frame_sizes[] = { - 0, // USBIF_CMDONLY - 0, // USBIF_BULK - 128, // USBIF_ISO_1 - 384, // USBIF_ISO_2 - 640, // USBIF_ISO_3 - 768, // USBIF_ISO_4 - 896, // USBIF_ISO_5 - 1023, // USBIF_ISO_6 -}; - -#define FRAMES_PER_DESC 10 -#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt] - -static void process_frame(struct camera_data *cam); -static void cpia2_usb_complete(struct urb *urb); -static int cpia2_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void cpia2_usb_disconnect(struct usb_interface *intf); -static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message); -static int cpia2_usb_resume(struct usb_interface *intf); - -static void free_sbufs(struct camera_data *cam); -static void add_APPn(struct camera_data *cam); -static void add_COM(struct camera_data *cam); -static int submit_urbs(struct camera_data *cam); -static int set_alternate(struct camera_data *cam, unsigned int alt); -static int configure_transfer_mode(struct camera_data *cam, unsigned int alt); - -static const struct usb_device_id cpia2_id_table[] = { - {USB_DEVICE(0x0553, 0x0100)}, - {USB_DEVICE(0x0553, 0x0140)}, - {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */ - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, cpia2_id_table); - -static struct usb_driver cpia2_driver = { - .name = "cpia2", - .probe = cpia2_usb_probe, - .disconnect = cpia2_usb_disconnect, - .suspend = cpia2_usb_suspend, - .resume = cpia2_usb_resume, - .reset_resume = cpia2_usb_resume, - .id_table = cpia2_id_table -}; - - -/****************************************************************************** - * - * process_frame - * - *****************************************************************************/ -static void process_frame(struct camera_data *cam) -{ - static int frame_count; - - unsigned char *inbuff = cam->workbuff->data; - - DBG("Processing frame #%d, current:%d\n", - cam->workbuff->num, cam->curbuff->num); - - if(cam->workbuff->length > cam->workbuff->max_length) - cam->workbuff->max_length = cam->workbuff->length; - - if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) { - frame_count++; - } else { - cam->workbuff->status = FRAME_ERROR; - DBG("Start of frame not found\n"); - return; - } - - /*** - * Now the output buffer should have a JPEG image in it. - ***/ - if(!cam->first_image_seen) { - /* Always skip the first image after streaming - * starts. It is almost certainly corrupt. */ - cam->first_image_seen = 1; - cam->workbuff->status = FRAME_EMPTY; - return; - } - if (cam->workbuff->length > 3) { - if(cam->mmapped && - cam->workbuff->length < cam->workbuff->max_length) { - /* No junk in the buffers */ - memset(cam->workbuff->data+cam->workbuff->length, - 0, cam->workbuff->max_length- - cam->workbuff->length); - } - cam->workbuff->max_length = cam->workbuff->length; - cam->workbuff->status = FRAME_READY; - - if(!cam->mmapped && cam->num_frames > 2) { - /* During normal reading, the most recent - * frame will be read. If the current frame - * hasn't started reading yet, it will never - * be read, so mark it empty. If the buffer is - * mmapped, or we have few buffers, we need to - * wait for the user to free the buffer. - * - * NOTE: This is not entirely foolproof with 3 - * buffers, but it would take an EXTREMELY - * overloaded system to cause problems (possible - * image data corruption). Basically, it would - * need to take more time to execute cpia2_read - * than it would for the camera to send - * cam->num_frames-2 frames before problems - * could occur. - */ - cam->curbuff->status = FRAME_EMPTY; - } - cam->curbuff = cam->workbuff; - cam->workbuff = cam->workbuff->next; - DBG("Changed buffers, work:%d, current:%d\n", - cam->workbuff->num, cam->curbuff->num); - return; - } else { - DBG("Not enough data for an image.\n"); - } - - cam->workbuff->status = FRAME_ERROR; - return; -} - -/****************************************************************************** - * - * add_APPn - * - * Adds a user specified APPn record - *****************************************************************************/ -static void add_APPn(struct camera_data *cam) -{ - if(cam->APP_len > 0) { - cam->workbuff->data[cam->workbuff->length++] = 0xFF; - cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn; - cam->workbuff->data[cam->workbuff->length++] = 0; - cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2; - memcpy(cam->workbuff->data+cam->workbuff->length, - cam->APP_data, cam->APP_len); - cam->workbuff->length += cam->APP_len; - } -} - -/****************************************************************************** - * - * add_COM - * - * Adds a user specified COM record - *****************************************************************************/ -static void add_COM(struct camera_data *cam) -{ - if(cam->COM_len > 0) { - cam->workbuff->data[cam->workbuff->length++] = 0xFF; - cam->workbuff->data[cam->workbuff->length++] = 0xFE; - cam->workbuff->data[cam->workbuff->length++] = 0; - cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2; - memcpy(cam->workbuff->data+cam->workbuff->length, - cam->COM_data, cam->COM_len); - cam->workbuff->length += cam->COM_len; - } -} - -/****************************************************************************** - * - * cpia2_usb_complete - * - * callback when incoming packet is received - *****************************************************************************/ -static void cpia2_usb_complete(struct urb *urb) -{ - int i; - unsigned char *cdata; - static bool frame_ready = false; - struct camera_data *cam = (struct camera_data *) urb->context; - - if (urb->status!=0) { - if (!(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) - { - DBG("urb->status = %d!\n", urb->status); - } - DBG("Stopping streaming\n"); - return; - } - - if (!cam->streaming || !video_is_registered(&cam->vdev)) { - LOG("Will now stop the streaming: streaming = %d, present=%d\n", - cam->streaming, video_is_registered(&cam->vdev)); - return; - } - - /*** - * Packet collater - ***/ - //DBG("Collating %d packets\n", urb->number_of_packets); - for (i = 0; i < urb->number_of_packets; i++) { - u16 checksum, iso_checksum; - int j; - int n = urb->iso_frame_desc[i].actual_length; - int st = urb->iso_frame_desc[i].status; - - if(cam->workbuff->status == FRAME_READY) { - struct framebuf *ptr; - /* Try to find an available buffer */ - DBG("workbuff full, searching\n"); - for (ptr = cam->workbuff->next; - ptr != cam->workbuff; - ptr = ptr->next) - { - if (ptr->status == FRAME_EMPTY) { - ptr->status = FRAME_READING; - ptr->length = 0; - break; - } - } - if (ptr == cam->workbuff) - break; /* No READING or EMPTY buffers left */ - - cam->workbuff = ptr; - } - - if (cam->workbuff->status == FRAME_EMPTY || - cam->workbuff->status == FRAME_ERROR) { - cam->workbuff->status = FRAME_READING; - cam->workbuff->length = 0; - } - - //DBG(" Packet %d length = %d, status = %d\n", i, n, st); - cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - if (st) { - LOG("cpia2 data error: [%d] len=%d, status = %d\n", - i, n, st); - if(!ALLOW_CORRUPT) - cam->workbuff->status = FRAME_ERROR; - continue; - } - - if(n<=2) - continue; - - checksum = 0; - for(j=0; j<n-2; ++j) - checksum += cdata[j]; - iso_checksum = cdata[j] + cdata[j+1]*256; - if(checksum != iso_checksum) { - LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n", - i, n, (int)checksum, (int)iso_checksum); - if(!ALLOW_CORRUPT) { - cam->workbuff->status = FRAME_ERROR; - continue; - } - } - n -= 2; - - if(cam->workbuff->status != FRAME_READING) { - if((0xFF == cdata[0] && 0xD8 == cdata[1]) || - (0xD8 == cdata[0] && 0xFF == cdata[1] && - 0 != cdata[2])) { - /* frame is skipped, but increment total - * frame count anyway */ - cam->frame_count++; - } - DBG("workbuff not reading, status=%d\n", - cam->workbuff->status); - continue; - } - - if (cam->frame_size < cam->workbuff->length + n) { - ERR("buffer overflow! length: %d, n: %d\n", - cam->workbuff->length, n); - cam->workbuff->status = FRAME_ERROR; - if(cam->workbuff->length > cam->workbuff->max_length) - cam->workbuff->max_length = - cam->workbuff->length; - continue; - } - - if (cam->workbuff->length == 0) { - int data_offset; - if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) { - data_offset = 1; - } else if((0xFF == cdata[0]) && (0xD8 == cdata[1]) - && (0xFF == cdata[2])) { - data_offset = 2; - } else { - DBG("Ignoring packet, not beginning!\n"); - continue; - } - DBG("Start of frame pattern found\n"); - cam->workbuff->ts = ktime_get_ns(); - cam->workbuff->seq = cam->frame_count++; - cam->workbuff->data[0] = 0xFF; - cam->workbuff->data[1] = 0xD8; - cam->workbuff->length = 2; - add_APPn(cam); - add_COM(cam); - memcpy(cam->workbuff->data+cam->workbuff->length, - cdata+data_offset, n-data_offset); - cam->workbuff->length += n-data_offset; - } else if (cam->workbuff->length > 0) { - memcpy(cam->workbuff->data + cam->workbuff->length, - cdata, n); - cam->workbuff->length += n; - } - - if ((cam->workbuff->length >= 3) && - (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) && - (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) && - (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) { - frame_ready = true; - cam->workbuff->data[cam->workbuff->length - 1] = 0; - cam->workbuff->length -= 1; - } else if ((cam->workbuff->length >= 2) && - (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) && - (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) { - frame_ready = true; - } - - if (frame_ready) { - DBG("Workbuff image size = %d\n",cam->workbuff->length); - process_frame(cam); - - frame_ready = false; - - if (waitqueue_active(&cam->wq_stream)) - wake_up_interruptible(&cam->wq_stream); - } - } - - if(cam->streaming) { - /* resubmit */ - urb->dev = cam->dev; - if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) - ERR("%s: usb_submit_urb ret %d!\n", __func__, i); - } -} - -/****************************************************************************** - * - * configure_transfer_mode - * - *****************************************************************************/ -static int configure_transfer_mode(struct camera_data *cam, unsigned int alt) -{ - static unsigned char iso_regs[8][4] = { - {0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00}, - {0xB9, 0x00, 0x00, 0x7E}, - {0xB9, 0x00, 0x01, 0x7E}, - {0xB9, 0x00, 0x02, 0x7E}, - {0xB9, 0x00, 0x02, 0xFE}, - {0xB9, 0x00, 0x03, 0x7E}, - {0xB9, 0x00, 0x03, 0xFD} - }; - struct cpia2_command cmd; - unsigned char reg; - - if (!video_is_registered(&cam->vdev)) - return -ENODEV; - - /*** - * Write the isoc registers according to the alternate selected - ***/ - cmd.direction = TRANSFER_WRITE; - cmd.buffer.block_data[0] = iso_regs[alt][0]; - cmd.buffer.block_data[1] = iso_regs[alt][1]; - cmd.buffer.block_data[2] = iso_regs[alt][2]; - cmd.buffer.block_data[3] = iso_regs[alt][3]; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.start = CPIA2_VC_USB_ISOLIM; - cmd.reg_count = 4; - cpia2_send_command(cam, &cmd); - - /*** - * Enable relevant streams before starting polling. - * First read USB Stream Config Register. - ***/ - cmd.direction = TRANSFER_READ; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cmd.start = CPIA2_VC_USB_STRM; - cmd.reg_count = 1; - cpia2_send_command(cam, &cmd); - reg = cmd.buffer.block_data[0]; - - /* Clear iso, bulk, and int */ - reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE | - CPIA2_VC_USB_STRM_ISO_ENABLE | - CPIA2_VC_USB_STRM_INT_ENABLE); - - if (alt == USBIF_BULK) { - DBG("Enabling bulk xfer\n"); - reg |= CPIA2_VC_USB_STRM_BLK_ENABLE; /* Enable Bulk */ - cam->xfer_mode = XFER_BULK; - } else if (alt >= USBIF_ISO_1) { - DBG("Enabling ISOC xfer\n"); - reg |= CPIA2_VC_USB_STRM_ISO_ENABLE; - cam->xfer_mode = XFER_ISOC; - } - - cmd.buffer.block_data[0] = reg; - cmd.direction = TRANSFER_WRITE; - cmd.start = CPIA2_VC_USB_STRM; - cmd.reg_count = 1; - cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; - cpia2_send_command(cam, &cmd); - - return 0; -} - -/****************************************************************************** - * - * cpia2_usb_change_streaming_alternate - * - *****************************************************************************/ -int cpia2_usb_change_streaming_alternate(struct camera_data *cam, - unsigned int alt) -{ - int ret = 0; - - if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6) - return -EINVAL; - - if(alt == cam->params.camera_state.stream_mode) - return 0; - - cpia2_usb_stream_pause(cam); - - configure_transfer_mode(cam, alt); - - cam->params.camera_state.stream_mode = alt; - - /* Reset the camera to prevent image quality degradation */ - cpia2_reset_camera(cam); - - cpia2_usb_stream_resume(cam); - - return ret; -} - -/****************************************************************************** - * - * set_alternate - * - *****************************************************************************/ -static int set_alternate(struct camera_data *cam, unsigned int alt) -{ - int ret = 0; - - if(alt == cam->cur_alt) - return 0; - - if (cam->cur_alt != USBIF_CMDONLY) { - DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY); - ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY); - if (ret != 0) - return ret; - } - if (alt != USBIF_CMDONLY) { - DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt); - ret = usb_set_interface(cam->dev, cam->iface, alt); - if (ret != 0) - return ret; - } - - cam->old_alt = cam->cur_alt; - cam->cur_alt = alt; - - return ret; -} - -/****************************************************************************** - * - * free_sbufs - * - * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL - * are assumed to be allocated. Non-NULL .urb members are also assumed to be - * submitted (and must therefore be killed before they are freed). - *****************************************************************************/ -static void free_sbufs(struct camera_data *cam) -{ - int i; - - for (i = 0; i < NUM_SBUF; i++) { - if(cam->sbuf[i].urb) { - usb_kill_urb(cam->sbuf[i].urb); - usb_free_urb(cam->sbuf[i].urb); - cam->sbuf[i].urb = NULL; - } - if(cam->sbuf[i].data) { - kfree(cam->sbuf[i].data); - cam->sbuf[i].data = NULL; - } - } -} - -/******* -* Convenience functions -*******/ -/**************************************************************************** - * - * write_packet - * - ***************************************************************************/ -static int write_packet(struct usb_device *udev, - u8 request, u8 * registers, u16 start, size_t size) -{ - unsigned char *buf; - int ret; - - if (!registers || size <= 0) - return -EINVAL; - - buf = kmemdup(registers, size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - start, /* value */ - 0, /* index */ - buf, /* buffer */ - size, - 1000); - - kfree(buf); - return ret; -} - -/**************************************************************************** - * - * read_packet - * - ***************************************************************************/ -static int read_packet(struct usb_device *udev, - u8 request, u8 * registers, u16 start, size_t size) -{ - unsigned char *buf; - int ret; - - if (!registers || size <= 0) - return -EINVAL; - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - request, - USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE, - start, /* value */ - 0, /* index */ - buf, /* buffer */ - size, - 1000); - - if (ret >= 0) - memcpy(registers, buf, size); - - kfree(buf); - - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_transfer_cmd - * - *****************************************************************************/ -int cpia2_usb_transfer_cmd(struct camera_data *cam, - void *registers, - u8 request, u8 start, u8 count, u8 direction) -{ - int err = 0; - struct usb_device *udev = cam->dev; - - if (!udev) { - ERR("%s: Internal driver error: udev is NULL\n", __func__); - return -EINVAL; - } - - if (!registers) { - ERR("%s: Internal driver error: register array is NULL\n", __func__); - return -EINVAL; - } - - if (direction == TRANSFER_READ) { - err = read_packet(udev, request, (u8 *)registers, start, count); - if (err > 0) - err = 0; - } else if (direction == TRANSFER_WRITE) { - err =write_packet(udev, request, (u8 *)registers, start, count); - if (err < 0) { - LOG("Control message failed, err val = %d\n", err); - LOG("Message: request = 0x%0X, start = 0x%0X\n", - request, start); - LOG("Message: count = %d, register[0] = 0x%0X\n", - count, ((unsigned char *) registers)[0]); - } else - err=0; - } else { - LOG("Unexpected first byte of direction: %d\n", - direction); - return -EINVAL; - } - - if(err != 0) - LOG("Unexpected error: %d\n", err); - return err; -} - - -/****************************************************************************** - * - * submit_urbs - * - *****************************************************************************/ -static int submit_urbs(struct camera_data *cam) -{ - struct urb *urb; - int fx, err, i, j; - - for(i=0; i<NUM_SBUF; ++i) { - if (cam->sbuf[i].data) - continue; - cam->sbuf[i].data = - kmalloc_array(FRAME_SIZE_PER_DESC, FRAMES_PER_DESC, - GFP_KERNEL); - if (!cam->sbuf[i].data) { - while (--i >= 0) { - kfree(cam->sbuf[i].data); - cam->sbuf[i].data = NULL; - } - return -ENOMEM; - } - } - - /* We double buffer the Isoc lists, and also know the polling - * interval is every frame (1 == (1 << (bInterval -1))). - */ - for(i=0; i<NUM_SBUF; ++i) { - if(cam->sbuf[i].urb) { - continue; - } - urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); - if (!urb) { - for (j = 0; j < i; j++) - usb_free_urb(cam->sbuf[j].urb); - for (j = 0; j < NUM_SBUF; j++) { - kfree(cam->sbuf[j].data); - cam->sbuf[j].data = NULL; - } - return -ENOMEM; - } - - cam->sbuf[i].urb = urb; - urb->dev = cam->dev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = cam->sbuf[i].data; - urb->complete = cpia2_usb_complete; - urb->number_of_packets = FRAMES_PER_DESC; - urb->interval = 1; - urb->transfer_buffer_length = - FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; - - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = - FRAME_SIZE_PER_DESC * fx; - urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; - } - } - - - /* Queue the ISO urbs, and resubmit in the completion handler */ - for(i=0; i<NUM_SBUF; ++i) { - err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL); - if (err) { - ERR("usb_submit_urb[%d]() = %d\n", i, err); - return err; - } - } - - return 0; -} - -/****************************************************************************** - * - * cpia2_usb_stream_start - * - *****************************************************************************/ -int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate) -{ - int ret; - int old_alt; - - if(cam->streaming) - return 0; - - if (cam->flush) { - int i; - DBG("Flushing buffers\n"); - for(i=0; i<cam->num_frames; ++i) { - cam->buffers[i].status = FRAME_EMPTY; - cam->buffers[i].length = 0; - } - cam->curbuff = &cam->buffers[0]; - cam->workbuff = cam->curbuff->next; - cam->flush = false; - } - - old_alt = cam->params.camera_state.stream_mode; - cam->params.camera_state.stream_mode = 0; - ret = cpia2_usb_change_streaming_alternate(cam, alternate); - if (ret < 0) { - int ret2; - ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret); - cam->params.camera_state.stream_mode = old_alt; - ret2 = set_alternate(cam, USBIF_CMDONLY); - if (ret2 < 0) { - ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already failed. Then tried to call set_alternate(USBIF_CMDONLY) = %d.\n", - alternate, ret, ret2); - } - } else { - cam->frame_count = 0; - cam->streaming = 1; - ret = cpia2_usb_stream_resume(cam); - } - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_stream_pause - * - *****************************************************************************/ -int cpia2_usb_stream_pause(struct camera_data *cam) -{ - int ret = 0; - if(cam->streaming) { - free_sbufs(cam); - ret = set_alternate(cam, USBIF_CMDONLY); - } - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_stream_resume - * - *****************************************************************************/ -int cpia2_usb_stream_resume(struct camera_data *cam) -{ - int ret = 0; - if(cam->streaming) { - cam->first_image_seen = 0; - ret = set_alternate(cam, cam->params.camera_state.stream_mode); - if(ret == 0) { - /* for some reason the user effects need to be set - again when starting streaming. */ - cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, - cam->params.vp_params.user_effects); - ret = submit_urbs(cam); - } - } - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_stream_stop - * - *****************************************************************************/ -int cpia2_usb_stream_stop(struct camera_data *cam) -{ - int ret; - - ret = cpia2_usb_stream_pause(cam); - cam->streaming = 0; - configure_transfer_mode(cam, 0); - return ret; -} - -/****************************************************************************** - * - * cpia2_usb_probe - * - * Probe and initialize. - *****************************************************************************/ -static int cpia2_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_interface_descriptor *interface; - struct camera_data *cam; - int ret; - - /* A multi-config CPiA2 camera? */ - if (udev->descriptor.bNumConfigurations != 1) - return -ENODEV; - interface = &intf->cur_altsetting->desc; - - /* If we get to this point, we found a CPiA2 camera */ - LOG("CPiA2 USB camera found\n"); - - cam = cpia2_init_camera_struct(intf); - if (cam == NULL) - return -ENOMEM; - - cam->dev = udev; - cam->iface = interface->bInterfaceNumber; - - ret = set_alternate(cam, USBIF_CMDONLY); - if (ret < 0) { - ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret); - goto alt_err; - } - - - if((ret = cpia2_init_camera(cam)) < 0) { - ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret); - goto alt_err; - } - LOG(" CPiA Version: %d.%02d (%d.%d)\n", - cam->params.version.firmware_revision_hi, - cam->params.version.firmware_revision_lo, - cam->params.version.asic_id, - cam->params.version.asic_rev); - LOG(" CPiA PnP-ID: %04x:%04x:%04x\n", - cam->params.pnp_id.vendor, - cam->params.pnp_id.product, - cam->params.pnp_id.device_revision); - LOG(" SensorID: %d.(version %d)\n", - cam->params.version.sensor_flags, - cam->params.version.sensor_rev); - - usb_set_intfdata(intf, cam); - - ret = cpia2_register_camera(cam); - if (ret < 0) { - ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret); - goto alt_err; - } - - return 0; - -alt_err: - cpia2_deinit_camera_struct(cam, intf); - return ret; -} - -/****************************************************************************** - * - * cpia2_disconnect - * - *****************************************************************************/ -static void cpia2_usb_disconnect(struct usb_interface *intf) -{ - struct camera_data *cam = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - - DBG("Stopping stream\n"); - cpia2_usb_stream_stop(cam); - - mutex_lock(&cam->v4l2_lock); - DBG("Unregistering camera\n"); - cpia2_unregister_camera(cam); - v4l2_device_disconnect(&cam->v4l2_dev); - mutex_unlock(&cam->v4l2_lock); - - if(cam->buffers) { - DBG("Wakeup waiting processes\n"); - cam->curbuff->status = FRAME_READY; - cam->curbuff->length = 0; - wake_up_interruptible(&cam->wq_stream); - } - - v4l2_device_put(&cam->v4l2_dev); - - LOG("CPiA2 camera disconnected.\n"); -} - -static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct camera_data *cam = usb_get_intfdata(intf); - - mutex_lock(&cam->v4l2_lock); - if (cam->streaming) { - cpia2_usb_stream_stop(cam); - cam->streaming = 1; - } - mutex_unlock(&cam->v4l2_lock); - - dev_info(&intf->dev, "going into suspend..\n"); - return 0; -} - -/* Resume device - start device. */ -static int cpia2_usb_resume(struct usb_interface *intf) -{ - struct camera_data *cam = usb_get_intfdata(intf); - - mutex_lock(&cam->v4l2_lock); - v4l2_ctrl_handler_setup(&cam->hdl); - if (cam->streaming) { - cam->streaming = 0; - cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - } - mutex_unlock(&cam->v4l2_lock); - - dev_info(&intf->dev, "coming out of suspend..\n"); - return 0; -} - -/****************************************************************************** - * - * usb_cpia2_init - * - *****************************************************************************/ -int cpia2_usb_init(void) -{ - return usb_register(&cpia2_driver); -} - -/****************************************************************************** - * - * usb_cpia_cleanup - * - *****************************************************************************/ -void cpia2_usb_cleanup(void) -{ - schedule_timeout(2 * HZ); - usb_deregister(&cpia2_driver); -} diff --git a/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c b/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c deleted file mode 100644 index 926ecfc9b64a..000000000000 --- a/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c +++ /dev/null @@ -1,1226 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/**************************************************************************** - * - * Filename: cpia2_v4l.c - * - * Copyright 2001, STMicrolectronics, Inc. - * Contact: steve.miller@st.com - * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> - * - * Description: - * This is a USB driver for CPia2 based video cameras. - * The infrastructure of this driver is based on the cpia usb driver by - * Jochen Scharrlach and Johannes Erdfeldt. - * - * Stripped of 2.4 stuff ready for main kernel submit by - * Alan Cox <alan@lxorguk.ukuu.org.uk> - ****************************************************************************/ - -#define CPIA_VERSION "3.0.1" - -#include <linux/module.h> -#include <linux/time.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/videodev2.h> -#include <linux/stringify.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-event.h> - -#include "cpia2.h" - -static int video_nr = -1; -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)"); - -static int buffer_size = 68 * 1024; -module_param(buffer_size, int, 0); -MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); - -static int num_buffers = 3; -module_param(num_buffers, int, 0); -MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" - __stringify(VIDEO_MAX_FRAME) ", default 3)"); - -static int alternate = DEFAULT_ALT; -module_param(alternate, int, 0); -MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" - __stringify(USBIF_ISO_6) ", default " - __stringify(DEFAULT_ALT) ")"); - -static int flicker_mode; -module_param(flicker_mode, int, 0); -MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or " - __stringify(60) ", default 0)"); - -MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); -MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(CPIA_VERSION); - -#define ABOUT "V4L-Driver for Vision CPiA2 based cameras" -#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000) - -/****************************************************************************** - * - * cpia2_open - * - *****************************************************************************/ -static int cpia2_open(struct file *file) -{ - struct camera_data *cam = video_drvdata(file); - int retval; - - if (mutex_lock_interruptible(&cam->v4l2_lock)) - return -ERESTARTSYS; - retval = v4l2_fh_open(file); - if (retval) - goto open_unlock; - - if (v4l2_fh_is_singular_file(file)) { - if (cpia2_allocate_buffers(cam)) { - v4l2_fh_release(file); - retval = -ENOMEM; - goto open_unlock; - } - - /* reset the camera */ - if (cpia2_reset_camera(cam) < 0) { - v4l2_fh_release(file); - retval = -EIO; - goto open_unlock; - } - - cam->APP_len = 0; - cam->COM_len = 0; - } - - cpia2_dbg_dump_registers(cam); -open_unlock: - mutex_unlock(&cam->v4l2_lock); - return retval; -} - -/****************************************************************************** - * - * cpia2_close - * - *****************************************************************************/ -static int cpia2_close(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct camera_data *cam = video_get_drvdata(dev); - - mutex_lock(&cam->v4l2_lock); - if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) { - cpia2_usb_stream_stop(cam); - - /* save camera state for later open */ - cpia2_save_camera_state(cam); - - cpia2_set_low_power(cam); - cpia2_free_buffers(cam); - } - - if (cam->stream_fh == file->private_data) { - cam->stream_fh = NULL; - cam->mmapped = 0; - } - mutex_unlock(&cam->v4l2_lock); - return v4l2_fh_release(file); -} - -/****************************************************************************** - * - * cpia2_v4l_read - * - *****************************************************************************/ -static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, - loff_t *off) -{ - struct camera_data *cam = video_drvdata(file); - int noblock = file->f_flags & O_NONBLOCK; - ssize_t ret; - - if (!cam) - return -EINVAL; - - if (mutex_lock_interruptible(&cam->v4l2_lock)) - return -ERESTARTSYS; - ret = cpia2_read(cam, buf, count, noblock); - mutex_unlock(&cam->v4l2_lock); - return ret; -} - -/****************************************************************************** - * - * cpia2_v4l_poll - * - *****************************************************************************/ -static __poll_t cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) -{ - struct camera_data *cam = video_drvdata(filp); - __poll_t res; - - mutex_lock(&cam->v4l2_lock); - res = cpia2_poll(cam, filp, wait); - mutex_unlock(&cam->v4l2_lock); - return res; -} - -static int sync(struct camera_data *cam, int frame_nr) -{ - struct framebuf *frame = &cam->buffers[frame_nr]; - - while (1) { - if (frame->status == FRAME_READY) - return 0; - - if (!cam->streaming) { - frame->status = FRAME_READY; - frame->length = 0; - return 0; - } - - mutex_unlock(&cam->v4l2_lock); - wait_event_interruptible(cam->wq_stream, - !cam->streaming || - frame->status == FRAME_READY); - mutex_lock(&cam->v4l2_lock); - if (signal_pending(current)) - return -ERESTARTSYS; - if (!video_is_registered(&cam->vdev)) - return -ENOTTY; - } -} - -/****************************************************************************** - * - * ioctl_querycap - * - * V4L2 device capabilities - * - *****************************************************************************/ - -static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc) -{ - struct camera_data *cam = video_drvdata(file); - - strscpy(vc->driver, "cpia2", sizeof(vc->driver)); - - if (cam->params.pnp_id.product == 0x151) - strscpy(vc->card, "QX5 Microscope", sizeof(vc->card)); - else - strscpy(vc->card, "CPiA2 Camera", sizeof(vc->card)); - switch (cam->params.pnp_id.device_type) { - case DEVICE_STV_672: - strcat(vc->card, " (672/"); - break; - case DEVICE_STV_676: - strcat(vc->card, " (676/"); - break; - default: - strcat(vc->card, " (XXX/"); - break; - } - switch (cam->params.version.sensor_flags) { - case CPIA2_VP_SENSOR_FLAGS_404: - strcat(vc->card, "404)"); - break; - case CPIA2_VP_SENSOR_FLAGS_407: - strcat(vc->card, "407)"); - break; - case CPIA2_VP_SENSOR_FLAGS_409: - strcat(vc->card, "409)"); - break; - case CPIA2_VP_SENSOR_FLAGS_410: - strcat(vc->card, "410)"); - break; - case CPIA2_VP_SENSOR_FLAGS_500: - strcat(vc->card, "500)"); - break; - default: - strcat(vc->card, "XXX)"); - break; - } - - if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) < 0) - memset(vc->bus_info, 0, sizeof(vc->bus_info)); - return 0; -} - -/****************************************************************************** - * - * ioctl_input - * - * V4L2 input get/set/enumerate - * - *****************************************************************************/ - -static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - if (i->index) - return -EINVAL; - strscpy(i->name, "Camera", sizeof(i->name)); - i->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - -static int cpia2_g_input(struct file *file, void *fh, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int cpia2_s_input(struct file *file, void *fh, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -/****************************************************************************** - * - * ioctl_enum_fmt - * - * V4L2 format enumerate - * - *****************************************************************************/ - -static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - if (f->index > 1) - return -EINVAL; - - if (f->index == 0) - f->pixelformat = V4L2_PIX_FMT_MJPEG; - else - f->pixelformat = V4L2_PIX_FMT_JPEG; - return 0; -} - -/****************************************************************************** - * - * ioctl_try_fmt - * - * V4L2 format try - * - *****************************************************************************/ - -static int cpia2_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct camera_data *cam = video_drvdata(file); - - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = cam->frame_size; - f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - - switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { - case VIDEOSIZE_VGA: - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - break; - case VIDEOSIZE_CIF: - f->fmt.pix.width = 352; - f->fmt.pix.height = 288; - break; - case VIDEOSIZE_QVGA: - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - break; - case VIDEOSIZE_288_216: - f->fmt.pix.width = 288; - f->fmt.pix.height = 216; - break; - case VIDEOSIZE_256_192: - f->fmt.pix.width = 256; - f->fmt.pix.height = 192; - break; - case VIDEOSIZE_224_168: - f->fmt.pix.width = 224; - f->fmt.pix.height = 168; - break; - case VIDEOSIZE_192_144: - f->fmt.pix.width = 192; - f->fmt.pix.height = 144; - break; - case VIDEOSIZE_QCIF: - default: - f->fmt.pix.width = 176; - f->fmt.pix.height = 144; - break; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_set_fmt - * - * V4L2 format set - * - *****************************************************************************/ - -static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh, - struct v4l2_format *f) -{ - struct camera_data *cam = video_drvdata(file); - int err, frame; - - err = cpia2_try_fmt_vid_cap(file, _fh, f); - if (err != 0) - return err; - - cam->pixelformat = f->fmt.pix.pixelformat; - - /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle - * the missing Huffman table properly. - */ - cam->params.compression.inhibit_htables = 0; - /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ - - /* we set the video window to something smaller or equal to what - * is requested by the user??? - */ - DBG("Requested width = %d, height = %d\n", - f->fmt.pix.width, f->fmt.pix.height); - if (f->fmt.pix.width != cam->width || - f->fmt.pix.height != cam->height) { - cam->width = f->fmt.pix.width; - cam->height = f->fmt.pix.height; - cam->params.roi.width = f->fmt.pix.width; - cam->params.roi.height = f->fmt.pix.height; - cpia2_set_format(cam); - } - - for (frame = 0; frame < cam->num_frames; ++frame) { - if (cam->buffers[frame].status == FRAME_READING) - if ((err = sync(cam, frame)) < 0) - return err; - - cam->buffers[frame].status = FRAME_EMPTY; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_get_fmt - * - * V4L2 format get - * - *****************************************************************************/ - -static int cpia2_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct camera_data *cam = video_drvdata(file); - - f->fmt.pix.width = cam->width; - f->fmt.pix.height = cam->height; - f->fmt.pix.pixelformat = cam->pixelformat; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = cam->frame_size; - f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - - return 0; -} - -/****************************************************************************** - * - * ioctl_cropcap - * - * V4L2 query cropping capabilities - * NOTE: cropping is currently disabled - * - *****************************************************************************/ - -static int cpia2_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct camera_data *cam = video_drvdata(file); - - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - switch (s->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - s->r.left = 0; - s->r.top = 0; - s->r.width = cam->width; - s->r.height = cam->height; - break; - default: - return -EINVAL; - } - return 0; -} - -struct framerate_info { - int value; - struct v4l2_fract period; -}; - -static const struct framerate_info framerate_controls[] = { - { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } }, - { CPIA2_VP_FRAMERATE_7_5, { 2, 15 } }, - { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } }, - { CPIA2_VP_FRAMERATE_15, { 1, 15 } }, - { CPIA2_VP_FRAMERATE_25, { 1, 25 } }, - { CPIA2_VP_FRAMERATE_30, { 1, 30 } }, -}; - -static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p) -{ - struct camera_data *cam = video_drvdata(file); - struct v4l2_captureparm *cap = &p->parm.capture; - int i; - - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - cap->capability = V4L2_CAP_TIMEPERFRAME; - cap->readbuffers = cam->num_frames; - for (i = 0; i < ARRAY_SIZE(framerate_controls); i++) - if (cam->params.vp_params.frame_rate == framerate_controls[i].value) { - cap->timeperframe = framerate_controls[i].period; - break; - } - return 0; -} - -static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p) -{ - struct camera_data *cam = video_drvdata(file); - struct v4l2_captureparm *cap = &p->parm.capture; - struct v4l2_fract tpf = cap->timeperframe; - int max = ARRAY_SIZE(framerate_controls) - 1; - int ret; - int i; - - ret = cpia2_g_parm(file, fh, p); - if (ret || !tpf.denominator || !tpf.numerator) - return ret; - - /* Maximum 15 fps for this model */ - if (cam->params.pnp_id.device_type == DEVICE_STV_672 && - cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) - max -= 2; - for (i = 0; i <= max; i++) { - struct v4l2_fract f1 = tpf; - struct v4l2_fract f2 = framerate_controls[i].period; - - f1.numerator *= f2.denominator; - f2.numerator *= f1.denominator; - if (f1.numerator >= f2.numerator) - break; - } - if (i > max) - i = max; - cap->timeperframe = framerate_controls[i].period; - return cpia2_set_fps(cam, framerate_controls[i].value); -} - -static const struct { - u32 width; - u32 height; -} cpia2_framesizes[] = { - { 640, 480 }, - { 352, 288 }, - { 320, 240 }, - { 288, 216 }, - { 256, 192 }, - { 224, 168 }, - { 192, 144 }, - { 176, 144 }, -}; - -static int cpia2_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG && - fsize->pixel_format != V4L2_PIX_FMT_JPEG) - return -EINVAL; - if (fsize->index >= ARRAY_SIZE(cpia2_framesizes)) - return -EINVAL; - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = cpia2_framesizes[fsize->index].width; - fsize->discrete.height = cpia2_framesizes[fsize->index].height; - - return 0; -} - -static int cpia2_enum_frameintervals(struct file *file, void *fh, - struct v4l2_frmivalenum *fival) -{ - struct camera_data *cam = video_drvdata(file); - int max = ARRAY_SIZE(framerate_controls) - 1; - int i; - - if (fival->pixel_format != V4L2_PIX_FMT_MJPEG && - fival->pixel_format != V4L2_PIX_FMT_JPEG) - return -EINVAL; - - /* Maximum 15 fps for this model */ - if (cam->params.pnp_id.device_type == DEVICE_STV_672 && - cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) - max -= 2; - if (fival->index > max) - return -EINVAL; - for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++) - if (fival->width == cpia2_framesizes[i].width && - fival->height == cpia2_framesizes[i].height) - break; - if (i == ARRAY_SIZE(cpia2_framesizes)) - return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete = framerate_controls[fival->index].period; - return 0; -} - -/****************************************************************************** - * - * ioctl_s_ctrl - * - * V4L2 set the value of a control variable - * - *****************************************************************************/ - -static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct camera_data *cam = - container_of(ctrl->handler, struct camera_data, hdl); - static const int flicker_table[] = { - NEVER_FLICKER, - FLICKER_50, - FLICKER_60, - }; - - DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - cpia2_set_brightness(cam, ctrl->val); - break; - case V4L2_CID_CONTRAST: - cpia2_set_contrast(cam, ctrl->val); - break; - case V4L2_CID_SATURATION: - cpia2_set_saturation(cam, ctrl->val); - break; - case V4L2_CID_HFLIP: - cpia2_set_property_mirror(cam, ctrl->val); - break; - case V4L2_CID_VFLIP: - cpia2_set_property_flip(cam, ctrl->val); - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]); - case V4L2_CID_ILLUMINATORS_1: - return cpia2_set_gpio(cam, (cam->top_light->val << 6) | - (cam->bottom_light->val << 7)); - case V4L2_CID_JPEG_ACTIVE_MARKER: - cam->params.compression.inhibit_htables = - !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT); - break; - case V4L2_CID_JPEG_COMPRESSION_QUALITY: - cam->params.vc_params.quality = ctrl->val; - break; - case CPIA2_CID_USB_ALT: - cam->params.camera_state.stream_mode = ctrl->val; - break; - default: - return -EINVAL; - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_g_jpegcomp - * - * V4L2 get the JPEG compression parameters - * - *****************************************************************************/ - -static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) -{ - struct camera_data *cam = video_drvdata(file); - - memset(parms, 0, sizeof(*parms)); - - parms->quality = 80; // TODO: Can this be made meaningful? - - parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; - if (!cam->params.compression.inhibit_htables) - parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; - - parms->APPn = cam->APPn; - parms->APP_len = cam->APP_len; - if (cam->APP_len > 0) { - memcpy(parms->APP_data, cam->APP_data, cam->APP_len); - parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; - } - - parms->COM_len = cam->COM_len; - if (cam->COM_len > 0) { - memcpy(parms->COM_data, cam->COM_data, cam->COM_len); - parms->jpeg_markers |= JPEG_MARKER_COM; - } - - DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", - parms->APP_len, parms->COM_len); - - return 0; -} - -/****************************************************************************** - * - * ioctl_s_jpegcomp - * - * V4L2 set the JPEG compression parameters - * NOTE: quality and some jpeg_markers are ignored. - * - *****************************************************************************/ - -static int cpia2_s_jpegcomp(struct file *file, void *fh, - const struct v4l2_jpegcompression *parms) -{ - struct camera_data *cam = video_drvdata(file); - - DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", - parms->APP_len, parms->COM_len); - - cam->params.compression.inhibit_htables = - !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); - - if (parms->APP_len != 0) { - if (parms->APP_len > 0 && - parms->APP_len <= sizeof(cam->APP_data) && - parms->APPn >= 0 && parms->APPn <= 15) { - cam->APPn = parms->APPn; - cam->APP_len = parms->APP_len; - memcpy(cam->APP_data, parms->APP_data, parms->APP_len); - } else { - LOG("Bad APPn Params n=%d len=%d\n", - parms->APPn, parms->APP_len); - return -EINVAL; - } - } else { - cam->APP_len = 0; - } - - if (parms->COM_len != 0) { - if (parms->COM_len > 0 && - parms->COM_len <= sizeof(cam->COM_data)) { - cam->COM_len = parms->COM_len; - memcpy(cam->COM_data, parms->COM_data, parms->COM_len); - } else { - LOG("Bad COM_len=%d\n", parms->COM_len); - return -EINVAL; - } - } - - return 0; -} - -/****************************************************************************** - * - * ioctl_reqbufs - * - * V4L2 Initiate memory mapping. - * NOTE: The user's request is ignored. For now the buffers are fixed. - * - *****************************************************************************/ - -static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) -{ - struct camera_data *cam = video_drvdata(file); - - if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); - req->count = cam->num_frames; - memset(&req->reserved, 0, sizeof(req->reserved)); - - return 0; -} - -/****************************************************************************** - * - * ioctl_querybuf - * - * V4L2 Query memory buffer status. - * - *****************************************************************************/ - -static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct camera_data *cam = video_drvdata(file); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->index >= cam->num_frames) - return -EINVAL; - - buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; - buf->length = cam->frame_size; - - buf->memory = V4L2_MEMORY_MMAP; - - if (cam->mmapped) - buf->flags = V4L2_BUF_FLAG_MAPPED; - else - buf->flags = 0; - - buf->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - - switch (cam->buffers[buf->index].status) { - case FRAME_EMPTY: - case FRAME_ERROR: - case FRAME_READING: - buf->bytesused = 0; - buf->flags = V4L2_BUF_FLAG_QUEUED; - break; - case FRAME_READY: - buf->bytesused = cam->buffers[buf->index].length; - v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts); - buf->sequence = cam->buffers[buf->index].seq; - buf->flags = V4L2_BUF_FLAG_DONE; - break; - } - - DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", - buf->index, buf->m.offset, buf->flags, buf->sequence, - buf->bytesused); - - return 0; -} - -/****************************************************************************** - * - * ioctl_qbuf - * - * V4L2 User is freeing buffer - * - *****************************************************************************/ - -static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct camera_data *cam = video_drvdata(file); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->memory != V4L2_MEMORY_MMAP || - buf->index >= cam->num_frames) - return -EINVAL; - - DBG("QBUF #%d\n", buf->index); - - if (cam->buffers[buf->index].status == FRAME_READY) - cam->buffers[buf->index].status = FRAME_EMPTY; - - return 0; -} - -/****************************************************************************** - * - * find_earliest_filled_buffer - * - * Helper for ioctl_dqbuf. Find the next ready buffer. - * - *****************************************************************************/ - -static int find_earliest_filled_buffer(struct camera_data *cam) -{ - int i; - int found = -1; - - for (i = 0; i < cam->num_frames; i++) { - if (cam->buffers[i].status == FRAME_READY) { - if (found < 0) { - found = i; - } else { - /* find which buffer is earlier */ - if (cam->buffers[i].ts < cam->buffers[found].ts) - found = i; - } - } - } - return found; -} - -/****************************************************************************** - * - * ioctl_dqbuf - * - * V4L2 User is asking for a filled buffer. - * - *****************************************************************************/ - -static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct camera_data *cam = video_drvdata(file); - int frame; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - frame = find_earliest_filled_buffer(cam); - - if (frame < 0 && file->f_flags & O_NONBLOCK) - return -EAGAIN; - - if (frame < 0) { - /* Wait for a frame to become available */ - struct framebuf *cb = cam->curbuff; - - mutex_unlock(&cam->v4l2_lock); - wait_event_interruptible(cam->wq_stream, - !video_is_registered(&cam->vdev) || - (cb = cam->curbuff)->status == FRAME_READY); - mutex_lock(&cam->v4l2_lock); - if (signal_pending(current)) - return -ERESTARTSYS; - if (!video_is_registered(&cam->vdev)) - return -ENOTTY; - frame = cb->num; - } - - buf->index = frame; - buf->bytesused = cam->buffers[buf->index].length; - buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE - | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - buf->field = V4L2_FIELD_NONE; - v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts); - buf->sequence = cam->buffers[buf->index].seq; - buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; - buf->length = cam->frame_size; - buf->reserved2 = 0; - buf->request_fd = 0; - memset(&buf->timecode, 0, sizeof(buf->timecode)); - - DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, - cam->buffers[buf->index].status, buf->sequence, buf->bytesused); - - return 0; -} - -static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct camera_data *cam = video_drvdata(file); - int ret = -EINVAL; - - DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); - if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (!cam->streaming) { - ret = cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - if (!ret) - v4l2_ctrl_grab(cam->usb_alt, true); - } - return ret; -} - -static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct camera_data *cam = video_drvdata(file); - int ret = -EINVAL; - - DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); - if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->streaming) { - ret = cpia2_usb_stream_stop(cam); - if (!ret) - v4l2_ctrl_grab(cam->usb_alt, false); - } - return ret; -} - -/****************************************************************************** - * - * cpia2_mmap - * - *****************************************************************************/ -static int cpia2_mmap(struct file *file, struct vm_area_struct *area) -{ - struct camera_data *cam = video_drvdata(file); - int retval; - - if (mutex_lock_interruptible(&cam->v4l2_lock)) - return -ERESTARTSYS; - retval = cpia2_remap_buffer(cam, area); - - if (!retval) - cam->stream_fh = file->private_data; - mutex_unlock(&cam->v4l2_lock); - return retval; -} - -/****************************************************************************** - * - * reset_camera_struct_v4l - * - * Sets all values to the defaults - *****************************************************************************/ -static void reset_camera_struct_v4l(struct camera_data *cam) -{ - cam->width = cam->params.roi.width; - cam->height = cam->params.roi.height; - - cam->frame_size = buffer_size; - cam->num_frames = num_buffers; - - /* Flicker modes */ - cam->params.flicker_control.flicker_mode_req = flicker_mode; - - /* stream modes */ - cam->params.camera_state.stream_mode = alternate; - - cam->pixelformat = V4L2_PIX_FMT_JPEG; -} - -static const struct v4l2_ioctl_ops cpia2_ioctl_ops = { - .vidioc_querycap = cpia2_querycap, - .vidioc_enum_input = cpia2_enum_input, - .vidioc_g_input = cpia2_g_input, - .vidioc_s_input = cpia2_s_input, - .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap, - .vidioc_g_jpegcomp = cpia2_g_jpegcomp, - .vidioc_s_jpegcomp = cpia2_s_jpegcomp, - .vidioc_g_selection = cpia2_g_selection, - .vidioc_reqbufs = cpia2_reqbufs, - .vidioc_querybuf = cpia2_querybuf, - .vidioc_qbuf = cpia2_qbuf, - .vidioc_dqbuf = cpia2_dqbuf, - .vidioc_streamon = cpia2_streamon, - .vidioc_streamoff = cpia2_streamoff, - .vidioc_s_parm = cpia2_s_parm, - .vidioc_g_parm = cpia2_g_parm, - .vidioc_enum_framesizes = cpia2_enum_framesizes, - .vidioc_enum_frameintervals = cpia2_enum_frameintervals, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -/*** - * The v4l video device structure initialized for this device - ***/ -static const struct v4l2_file_operations cpia2_fops = { - .owner = THIS_MODULE, - .open = cpia2_open, - .release = cpia2_close, - .read = cpia2_v4l_read, - .poll = cpia2_v4l_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = cpia2_mmap, -}; - -static const struct video_device cpia2_template = { - /* I could not find any place for the old .initialize initializer?? */ - .name = "CPiA2 Camera", - .fops = &cpia2_fops, - .ioctl_ops = &cpia2_ioctl_ops, - .release = video_device_release_empty, -}; - -void cpia2_camera_release(struct v4l2_device *v4l2_dev) -{ - struct camera_data *cam = - container_of(v4l2_dev, struct camera_data, v4l2_dev); - - v4l2_ctrl_handler_free(&cam->hdl); - v4l2_device_unregister(&cam->v4l2_dev); - kfree(cam); -} - -static const struct v4l2_ctrl_ops cpia2_ctrl_ops = { - .s_ctrl = cpia2_s_ctrl, -}; - -/****************************************************************************** - * - * cpia2_register_camera - * - *****************************************************************************/ -int cpia2_register_camera(struct camera_data *cam) -{ - struct v4l2_ctrl_handler *hdl = &cam->hdl; - struct v4l2_ctrl_config cpia2_usb_alt = { - .ops = &cpia2_ctrl_ops, - .id = CPIA2_CID_USB_ALT, - .name = "USB Alternate", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = USBIF_ISO_1, - .max = USBIF_ISO_6, - .step = 1, - }; - int ret; - - v4l2_ctrl_handler_init(hdl, 12); - v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_BRIGHTNESS, - cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0, - 255, 1, DEFAULT_BRIGHTNESS); - v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST); - v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION); - v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_JPEG_ACTIVE_MARKER, 0, - V4L2_JPEG_ACTIVE_MARKER_DHT, 0, - V4L2_JPEG_ACTIVE_MARKER_DHT); - v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, - 100, 1, 100); - cpia2_usb_alt.def = alternate; - cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL); - /* VP5 Only */ - if (cam->params.pnp_id.device_type != DEVICE_STV_672) - v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - /* Flicker control only valid for 672 */ - if (cam->params.pnp_id.device_type == DEVICE_STV_672) - v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops, - V4L2_CID_POWER_LINE_FREQUENCY, - V4L2_CID_POWER_LINE_FREQUENCY_60HZ, - 0, 0); - /* Light control only valid for the QX5 Microscope */ - if (cam->params.pnp_id.product == 0x151) { - cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_ILLUMINATORS_1, - 0, 1, 1, 0); - cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, - V4L2_CID_ILLUMINATORS_2, - 0, 1, 1, 0); - v4l2_ctrl_cluster(2, &cam->top_light); - } - - if (hdl->error) { - ret = hdl->error; - v4l2_ctrl_handler_free(hdl); - return ret; - } - - cam->vdev = cpia2_template; - video_set_drvdata(&cam->vdev, cam); - cam->vdev.lock = &cam->v4l2_lock; - cam->vdev.ctrl_handler = hdl; - cam->vdev.v4l2_dev = &cam->v4l2_dev; - cam->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - reset_camera_struct_v4l(cam); - - /* register v4l device */ - if (video_register_device(&cam->vdev, VFL_TYPE_VIDEO, video_nr) < 0) { - ERR("video_register_device failed\n"); - return -ENODEV; - } - - return 0; -} - -/****************************************************************************** - * - * cpia2_unregister_camera - * - *****************************************************************************/ -void cpia2_unregister_camera(struct camera_data *cam) -{ - video_unregister_device(&cam->vdev); -} - -/****************************************************************************** - * - * check_parameters - * - * Make sure that all user-supplied parameters are sensible - *****************************************************************************/ -static void __init check_parameters(void) -{ - if (buffer_size < PAGE_SIZE) { - buffer_size = PAGE_SIZE; - LOG("buffer_size too small, setting to %d\n", buffer_size); - } else if (buffer_size > 1024 * 1024) { - /* arbitrary upper limiit */ - buffer_size = 1024 * 1024; - LOG("buffer_size ridiculously large, setting to %d\n", - buffer_size); - } else { - buffer_size += PAGE_SIZE - 1; - buffer_size &= ~(PAGE_SIZE - 1); - } - - if (num_buffers < 1) { - num_buffers = 1; - LOG("num_buffers too small, setting to %d\n", num_buffers); - } else if (num_buffers > VIDEO_MAX_FRAME) { - num_buffers = VIDEO_MAX_FRAME; - LOG("num_buffers too large, setting to %d\n", num_buffers); - } - - if (alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { - alternate = DEFAULT_ALT; - LOG("alternate specified is invalid, using %d\n", alternate); - } - - if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) { - flicker_mode = 0; - LOG("Flicker mode specified is invalid, using %d\n", - flicker_mode); - } - - DBG("Using %d buffers, each %d bytes, alternate=%d\n", - num_buffers, buffer_size, alternate); -} - -/************ Module Stuff ***************/ - -/****************************************************************************** - * - * cpia2_init/module_init - * - *****************************************************************************/ -static int __init cpia2_init(void) -{ - LOG("%s v%s\n", - ABOUT, CPIA_VERSION); - check_parameters(); - return cpia2_usb_init(); -} - -/****************************************************************************** - * - * cpia2_exit/module_exit - * - *****************************************************************************/ -static void __exit cpia2_exit(void) -{ - cpia2_usb_cleanup(); - schedule_timeout(2 * HZ); -} - -module_init(cpia2_init); -module_exit(cpia2_exit); diff --git a/drivers/staging/media/deprecated/fsl-viu/Kconfig b/drivers/staging/media/deprecated/fsl-viu/Kconfig deleted file mode 100644 index 399892c69a18..000000000000 --- a/drivers/staging/media/deprecated/fsl-viu/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_VIU - tristate "NXP VIU Video Driver (DEPRECATED)" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C - select VIDEOBUF_DMA_CONTIG - help - Support for Freescale VIU video driver. This device captures - video data, or overlays video on DIU frame buffer. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - Say Y here if you want to enable VIU device on MPC5121e Rev2+. - In doubt, say N. diff --git a/drivers/staging/media/deprecated/fsl-viu/Makefile b/drivers/staging/media/deprecated/fsl-viu/Makefile deleted file mode 100644 index 931ec56ad08c..000000000000 --- a/drivers/staging/media/deprecated/fsl-viu/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o diff --git a/drivers/staging/media/deprecated/fsl-viu/TODO b/drivers/staging/media/deprecated/fsl-viu/TODO deleted file mode 100644 index ecb30a429689..000000000000 --- a/drivers/staging/media/deprecated/fsl-viu/TODO +++ /dev/null @@ -1,7 +0,0 @@ -This is one of the few drivers still not using the vb2 -framework, so this driver is now deprecated with the intent of -removing it altogether by the beginning of 2023. - -In order to keep this driver it has to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c b/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c deleted file mode 100644 index afc96f6db2a1..000000000000 --- a/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c +++ /dev/null @@ -1,1599 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * Freescale VIU video driver - * - * Authors: Hongjun Chen <hong-jun.chen@freescale.com> - * Porting to 2.6.35 by DENX Software Engineering, - * Anatolij Gustschin <agust@denx.de> - */ - -#include <linux/module.h> -#include <linux/clk.h> -#include <linux/kernel.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/of_platform.h> -#include <linux/slab.h> -#include <media/v4l2-common.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-fh.h> -#include <media/v4l2-event.h> -#include <media/videobuf-dma-contig.h> - -#define DRV_NAME "fsl_viu" -#define VIU_VERSION "0.5.1" - -#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ - -#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */ - -/* I2C address of video decoder chip is 0x4A */ -#define VIU_VIDEO_DECODER_ADDR 0x25 - -static int info_level; - -#define dprintk(level, fmt, arg...) \ - do { \ - if (level <= info_level) \ - printk(KERN_DEBUG "viu: " fmt , ## arg); \ - } while (0) - -/* - * Basic structures - */ -struct viu_fmt { - u32 fourcc; /* v4l2 format id */ - u32 pixelformat; - int depth; -}; - -static struct viu_fmt formats[] = { - { - .fourcc = V4L2_PIX_FMT_RGB565, - .pixelformat = V4L2_PIX_FMT_RGB565, - .depth = 16, - }, { - .fourcc = V4L2_PIX_FMT_RGB32, - .pixelformat = V4L2_PIX_FMT_RGB32, - .depth = 32, - } -}; - -struct viu_dev; -struct viu_buf; - -/* buffer for one video frame */ -struct viu_buf { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - struct viu_fmt *fmt; -}; - -struct viu_dmaqueue { - struct viu_dev *dev; - struct list_head active; - struct list_head queued; - struct timer_list timeout; -}; - -struct viu_status { - u32 field_irq; - u32 vsync_irq; - u32 hsync_irq; - u32 vstart_irq; - u32 dma_end_irq; - u32 error_irq; -}; - -struct viu_reg { - u32 status_cfg; - u32 luminance; - u32 chroma_r; - u32 chroma_g; - u32 chroma_b; - u32 field_base_addr; - u32 dma_inc; - u32 picture_count; - u32 req_alarm; - u32 alpha; -} __attribute__ ((packed)); - -struct viu_dev { - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler hdl; - struct mutex lock; - spinlock_t slock; - int users; - - struct device *dev; - /* various device info */ - struct video_device *vdev; - struct viu_dmaqueue vidq; - enum v4l2_field capfield; - int field; - int first; - int dma_done; - - /* Hardware register area */ - struct viu_reg __iomem *vr; - - /* Interrupt vector */ - int irq; - struct viu_status irqs; - - /* video overlay */ - struct v4l2_framebuffer ovbuf; - struct viu_fmt *ovfmt; - unsigned int ovenable; - enum v4l2_field ovfield; - - /* crop */ - struct v4l2_rect crop_current; - - /* clock pointer */ - struct clk *clk; - - /* decoder */ - struct v4l2_subdev *decoder; - - v4l2_std_id std; -}; - -struct viu_fh { - /* must remain the first field of this struct */ - struct v4l2_fh fh; - struct viu_dev *dev; - - /* video capture */ - struct videobuf_queue vb_vidq; - spinlock_t vbq_lock; /* spinlock for the videobuf queue */ - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip clips[1]; - - /* video capture */ - struct viu_fmt *fmt; - int width, height, sizeimage; - enum v4l2_buf_type type; -}; - -static struct viu_reg reg_val; - -/* - * Macro definitions of VIU registers - */ - -/* STATUS_CONFIG register */ -enum status_config { - SOFT_RST = 1 << 0, - - ERR_MASK = 0x0f << 4, /* Error code mask */ - ERR_NO = 0x00, /* No error */ - ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */ - ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */ - ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */ - ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */ - ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */ - ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */ - ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */ - ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */ - ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */ - ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */ - - INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */ - INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */ - INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */ - INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */ - INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */ - INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */ - INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */ - - INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */ - INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */ - INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */ - INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */ - INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */ - INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */ - - DMA_ACT = 0x01 << 27, /* Enable DMA transfer */ - FIELD_NO = 0x01 << 28, /* Field number */ - DITHER_ON = 0x01 << 29, /* Dithering is on */ - ROUND_ON = 0x01 << 30, /* Round is on */ - MODE_32BIT = 1UL << 31, /* Data in RGBa888, - * 0 in RGB565 - */ -}; - -#define norm_maxw() 720 -#define norm_maxh() 576 - -#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \ - INT_HSYNC_STATUS | INT_VSTART_STATUS | \ - INT_DMA_END_STATUS | INT_ERROR_STATUS) - -#define NUM_FORMATS ARRAY_SIZE(formats) - -static irqreturn_t viu_intr(int irq, void *dev_id); - -static struct viu_fmt *format_by_fourcc(int fourcc) -{ - int i; - - for (i = 0; i < NUM_FORMATS; i++) { - if (formats[i].pixelformat == fourcc) - return formats + i; - } - - dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc); - return NULL; -} - -static void viu_start_dma(struct viu_dev *dev) -{ - struct viu_reg __iomem *vr = dev->vr; - - dev->field = 0; - - /* Enable DMA operation */ - iowrite32be(SOFT_RST, &vr->status_cfg); - iowrite32be(INT_FIELD_EN, &vr->status_cfg); -} - -static void viu_stop_dma(struct viu_dev *dev) -{ - struct viu_reg __iomem *vr = dev->vr; - int cnt = 100; - u32 status_cfg; - - iowrite32be(0, &vr->status_cfg); - - /* Clear pending interrupts */ - status_cfg = ioread32be(&vr->status_cfg); - if (status_cfg & 0x3f0000) - iowrite32be(status_cfg & 0x3f0000, &vr->status_cfg); - - if (status_cfg & DMA_ACT) { - do { - status_cfg = ioread32be(&vr->status_cfg); - if (status_cfg & INT_DMA_END_STATUS) - break; - } while (cnt--); - - if (cnt < 0) { - /* timed out, issue soft reset */ - iowrite32be(SOFT_RST, &vr->status_cfg); - iowrite32be(0, &vr->status_cfg); - } else { - /* clear DMA_END and other pending irqs */ - iowrite32be(status_cfg & 0x3f0000, &vr->status_cfg); - } - } - - dev->field = 0; -} - -static int restart_video_queue(struct viu_dmaqueue *vidq) -{ - struct viu_buf *buf, *prev; - - dprintk(1, "%s vidq=%p\n", __func__, vidq); - if (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - - viu_stop_dma(vidq->dev); - - /* cancel all outstanding capture requests */ - list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) { - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - } - mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&vidq->queued)) - return 0; - buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue); - if (prev == NULL) { - list_move_tail(&buf->vb.queue, &vidq->active); - - dprintk(1, "Restarting video dma\n"); - viu_stop_dma(vidq->dev); - viu_start_dma(vidq->dev); - - buf->vb.state = VIDEOBUF_ACTIVE; - mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static void viu_vid_timeout(struct timer_list *t) -{ - struct viu_dev *dev = from_timer(dev, t, vidq.timeout); - struct viu_buf *buf; - struct viu_dmaqueue *vidq = &dev->vidq; - - while (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct viu_buf, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i); - } - - restart_video_queue(vidq); -} - -/* - * Videobuf operations - */ -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct viu_fh *fh = vq->priv_data; - - *size = fh->width * fh->height * fh->fmt->depth >> 3; - if (*count == 0) - *count = 32; - - while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024) - (*count)--; - - dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size); - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf) -{ - struct videobuf_buffer *vb = &buf->vb; - void *vaddr = NULL; - - videobuf_waiton(vq, &buf->vb, 0, 0); - - if (vq->int_ops && vq->int_ops->vaddr) - vaddr = vq->int_ops->vaddr(vb); - - if (vaddr) - videobuf_dma_contig_free(vq, &buf->vb); - - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf) -{ - struct viu_reg __iomem *vr = dev->vr; - int bpp; - - /* setup the DMA base address */ - reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb); - - dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n", - buf, buf->vb.i, (unsigned long)reg_val.field_base_addr); - - /* interlace is on by default, set horizontal DMA increment */ - reg_val.status_cfg = 0; - bpp = buf->fmt->depth >> 3; - switch (bpp) { - case 2: - reg_val.status_cfg &= ~MODE_32BIT; - reg_val.dma_inc = buf->vb.width * 2; - break; - case 4: - reg_val.status_cfg |= MODE_32BIT; - reg_val.dma_inc = buf->vb.width * 4; - break; - default: - dprintk(0, "doesn't support color depth(%d)\n", - bpp * 8); - return -EINVAL; - } - - /* setup picture_count register */ - reg_val.picture_count = (buf->vb.height / 2) << 16 | - buf->vb.width; - - reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; - - buf->vb.state = VIDEOBUF_ACTIVE; - dev->capfield = buf->vb.field; - - /* reset dma increment if needed */ - if (!V4L2_FIELD_HAS_BOTH(buf->vb.field)) - reg_val.dma_inc = 0; - - iowrite32be(reg_val.dma_inc, &vr->dma_inc); - iowrite32be(reg_val.picture_count, &vr->picture_count); - iowrite32be(reg_val.field_base_addr, &vr->field_base_addr); - mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT); - return 0; -} - -static int buffer_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct viu_fh *fh = vq->priv_data; - struct viu_buf *buf = container_of(vb, struct viu_buf, vb); - int rc; - - BUG_ON(fh->fmt == NULL); - - if (fh->width < 48 || fh->width > norm_maxw() || - fh->height < 32 || fh->height > norm_maxh()) - return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; - if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - } - - if (buf->vb.state == VIDEOBUF_NEEDS_INIT) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc != 0) - goto fail; - - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - buf->fmt = fh->fmt; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct viu_buf *buf = container_of(vb, struct viu_buf, vb); - struct viu_fh *fh = vq->priv_data; - struct viu_dev *dev = fh->dev; - struct viu_dmaqueue *vidq = &dev->vidq; - struct viu_buf *prev; - - if (!list_empty(&vidq->queued)) { - dprintk(1, "adding vb queue=%p\n", &buf->vb.queue); - dprintk(1, "vidq pointer 0x%p, queued 0x%p\n", - vidq, &vidq->queued); - dprintk(1, "dev %p, queued: self %p, next %p, head %p\n", - dev, &vidq->queued, vidq->queued.next, - vidq->queued.prev); - list_add_tail(&buf->vb.queue, &vidq->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - } else if (list_empty(&vidq->active)) { - dprintk(1, "adding vb active=%p\n", &buf->vb.queue); - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - - buffer_activate(dev, buf); - } else { - dprintk(1, "adding vb queue2=%p\n", &buf->vb.queue); - prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - } else { - list_add_tail(&buf->vb.queue, &vidq->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct viu_buf *buf = container_of(vb, struct viu_buf, vb); - struct viu_fh *fh = vq->priv_data; - struct viu_dev *dev = (struct viu_dev *)fh->dev; - - viu_stop_dma(dev); - free_buffer(vq, buf); -} - -static const struct videobuf_queue_ops viu_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* - * IOCTL vidioc handling - */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strscpy(cap->driver, "viu", sizeof(cap->driver)); - strscpy(cap->card, "viu", sizeof(cap->card)); - strscpy(cap->bus_info, "platform:viu", sizeof(cap->bus_info)); - return 0; -} - -static int vidioc_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int index = f->index; - - if (f->index >= NUM_FORMATS) - return -EINVAL; - - f->pixelformat = formats[index].fourcc; - return 0; -} - -static int vidioc_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vb_vidq.field; - f->fmt.pix.pixelformat = fh->fmt->pixelformat; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = fh->sizeimage; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int vidioc_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fmt *fmt; - unsigned int maxw, maxh; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (!fmt) { - dprintk(1, "Fourcc format (0x%08x) invalid.", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - maxw = norm_maxw(); - maxh = norm_maxh(); - - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - return 0; -} - -static int vidioc_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - int ret; - - ret = vidioc_try_fmt_cap(file, fh, f); - if (ret < 0) - return ret; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->sizeimage = f->fmt.pix.sizeimage; - fh->vb_vidq.field = f->fmt.pix.field; - fh->type = f->type; - return 0; -} - -static int vidioc_g_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - - f->fmt.win = fh->win; - return 0; -} - -static int verify_preview(struct viu_dev *dev, struct v4l2_window *win) -{ - enum v4l2_field field; - int maxw, maxh; - - if (dev->ovbuf.base == NULL) - return -EINVAL; - if (dev->ovfmt == NULL) - return -EINVAL; - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; - - field = win->field; - maxw = dev->crop_current.width; - maxh = dev->crop_current.height; - - if (field == V4L2_FIELD_ANY) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - win->field = field; - if (win->w.width > maxw) - win->w.width = maxw; - if (win->w.height > maxh) - win->w.height = maxh; - return 0; -} - -inline void viu_activate_overlay(struct viu_reg __iomem *vr) -{ - iowrite32be(reg_val.field_base_addr, &vr->field_base_addr); - iowrite32be(reg_val.dma_inc, &vr->dma_inc); - iowrite32be(reg_val.picture_count, &vr->picture_count); -} - -static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh) -{ - int bpp; - - dprintk(1, "%s %dx%d\n", __func__, - fh->win.w.width, fh->win.w.height); - - reg_val.status_cfg = 0; - - /* setup window */ - reg_val.picture_count = (fh->win.w.height / 2) << 16 | - fh->win.w.width; - - /* setup color depth and dma increment */ - bpp = dev->ovfmt->depth / 8; - switch (bpp) { - case 2: - reg_val.status_cfg &= ~MODE_32BIT; - reg_val.dma_inc = fh->win.w.width * 2; - break; - case 4: - reg_val.status_cfg |= MODE_32BIT; - reg_val.dma_inc = fh->win.w.width * 4; - break; - default: - dprintk(0, "device doesn't support color depth(%d)\n", - bpp * 8); - return -EINVAL; - } - - dev->ovfield = fh->win.field; - if (!V4L2_FIELD_HAS_BOTH(dev->ovfield)) - reg_val.dma_inc = 0; - - reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN; - - /* setup the base address of the overlay buffer */ - reg_val.field_base_addr = (u32)(long)dev->ovbuf.base; - - return 0; -} - -static int vidioc_s_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = (struct viu_dev *)fh->dev; - unsigned long flags; - int err; - - err = verify_preview(dev, &f->fmt.win); - if (err) - return err; - - fh->win = f->fmt.win; - - spin_lock_irqsave(&dev->slock, flags); - viu_setup_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - return 0; -} - -static int vidioc_try_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - return 0; -} - -static int vidioc_overlay(struct file *file, void *priv, unsigned int on) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = (struct viu_dev *)fh->dev; - unsigned long flags; - - if (on) { - spin_lock_irqsave(&dev->slock, flags); - viu_activate_overlay(dev->vr); - dev->ovenable = 1; - - /* start dma */ - viu_start_dma(dev); - spin_unlock_irqrestore(&dev->slock, flags); - } else { - viu_stop_dma(dev); - dev->ovenable = 0; - } - - return 0; -} - -static int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = fh->dev; - struct v4l2_framebuffer *fb = arg; - - *fb = dev->ovbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - return 0; -} - -static int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *arg) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = fh->dev; - const struct v4l2_framebuffer *fb = arg; - struct viu_fmt *fmt; - - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (fmt == NULL) - return -EINVAL; - - /* ok, accept it */ - dev->ovbuf = *fb; - dev->ovfmt = fmt; - if (dev->ovbuf.fmt.bytesperline == 0) { - dev->ovbuf.fmt.bytesperline = - dev->ovbuf.fmt.width * fmt->depth / 8; - } - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct viu_fh *fh = priv; - - return videobuf_reqbufs(&fh->vb_vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct viu_fh *fh = priv; - - return videobuf_querybuf(&fh->vb_vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct viu_fh *fh = priv; - - return videobuf_qbuf(&fh->vb_vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct viu_fh *fh = priv; - - return videobuf_dqbuf(&fh->vb_vidq, p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct viu_fh *fh = priv; - struct viu_dev *dev = fh->dev; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (fh->type != i) - return -EINVAL; - - if (dev->ovenable) - dev->ovenable = 0; - - viu_start_dma(fh->dev); - - return videobuf_streamon(&fh->vb_vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct viu_fh *fh = priv; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (fh->type != i) - return -EINVAL; - - viu_stop_dma(fh->dev); - - return videobuf_streamoff(&fh->vb_vidq); -} - -#define decoder_call(viu, o, f, args...) \ - v4l2_subdev_call(viu->decoder, o, f, ##args) - -static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct viu_fh *fh = priv; - - decoder_call(fh->dev, video, querystd, std_id); - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) -{ - struct viu_fh *fh = priv; - - fh->dev->std = id; - decoder_call(fh->dev, video, s_std, id); - return 0; -} - -static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct viu_fh *fh = priv; - - *std_id = fh->dev->std; - return 0; -} - -/* only one input in this driver */ -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct viu_fh *fh = priv; - - if (inp->index != 0) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = fh->dev->vdev->tvnorms; - strscpy(inp->name, "Camera", sizeof(inp->name)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct viu_fh *fh = priv; - - if (i) - return -EINVAL; - - decoder_call(fh->dev, video, s_routing, i, 0, 0); - return 0; -} - -inline void viu_activate_next_buf(struct viu_dev *dev, - struct viu_dmaqueue *viuq) -{ - struct viu_dmaqueue *vidq = viuq; - struct viu_buf *buf; - - /* launch another DMA operation for an active/queued buffer */ - if (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct viu_buf, - vb.queue); - dprintk(1, "start another queued buffer: 0x%p\n", buf); - buffer_activate(dev, buf); - } else if (!list_empty(&vidq->queued)) { - buf = list_entry(vidq->queued.next, struct viu_buf, - vb.queue); - list_del(&buf->vb.queue); - - dprintk(1, "start another queued buffer: 0x%p\n", buf); - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buffer_activate(dev, buf); - } -} - -inline void viu_default_settings(struct viu_reg __iomem *vr) -{ - iowrite32be(0x9512A254, &vr->luminance); - iowrite32be(0x03310000, &vr->chroma_r); - iowrite32be(0x06600F38, &vr->chroma_g); - iowrite32be(0x00000409, &vr->chroma_b); - iowrite32be(0x000000ff, &vr->alpha); - iowrite32be(0x00000090, &vr->req_alarm); - dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n", - ioread32be(&vr->status_cfg), ioread32be(&vr->field_base_addr)); -} - -static void viu_overlay_intr(struct viu_dev *dev, u32 status) -{ - struct viu_reg __iomem *vr = dev->vr; - - if (status & INT_DMA_END_STATUS) - dev->dma_done = 1; - - if (status & INT_FIELD_STATUS) { - if (dev->dma_done) { - u32 addr = reg_val.field_base_addr; - - dev->dma_done = 0; - if (status & FIELD_NO) - addr += reg_val.dma_inc; - - iowrite32be(addr, &vr->field_base_addr); - iowrite32be(reg_val.dma_inc, &vr->dma_inc); - iowrite32be((status & 0xffc0ffff) | - (status & INT_ALL_STATUS) | - reg_val.status_cfg, &vr->status_cfg); - } else if (status & INT_VSYNC_STATUS) { - iowrite32be((status & 0xffc0ffff) | - (status & INT_ALL_STATUS) | - reg_val.status_cfg, &vr->status_cfg); - } - } -} - -static void viu_capture_intr(struct viu_dev *dev, u32 status) -{ - struct viu_dmaqueue *vidq = &dev->vidq; - struct viu_reg __iomem *vr = dev->vr; - struct viu_buf *buf; - int field_num; - int need_two; - int dma_done = 0; - - field_num = status & FIELD_NO; - need_two = V4L2_FIELD_HAS_BOTH(dev->capfield); - - if (status & INT_DMA_END_STATUS) { - dma_done = 1; - if (((field_num == 0) && (dev->field == 0)) || - (field_num && (dev->field == 1))) - dev->field++; - } - - if (status & INT_FIELD_STATUS) { - dprintk(1, "irq: field %d, done %d\n", - !!field_num, dma_done); - if (unlikely(dev->first)) { - if (field_num == 0) { - dev->first = 0; - dprintk(1, "activate first buf\n"); - viu_activate_next_buf(dev, vidq); - } else - dprintk(1, "wait field 0\n"); - return; - } - - /* setup buffer address for next dma operation */ - if (!list_empty(&vidq->active)) { - u32 addr = reg_val.field_base_addr; - - if (field_num && need_two) { - addr += reg_val.dma_inc; - dprintk(1, "field 1, 0x%lx, dev field %d\n", - (unsigned long)addr, dev->field); - } - iowrite32be(addr, &vr->field_base_addr); - iowrite32be(reg_val.dma_inc, &vr->dma_inc); - iowrite32be((status & 0xffc0ffff) | - (status & INT_ALL_STATUS) | - reg_val.status_cfg, &vr->status_cfg); - return; - } - } - - if (dma_done && field_num && (dev->field == 2)) { - dev->field = 0; - buf = list_entry(vidq->active.next, - struct viu_buf, vb.queue); - dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n", - buf, buf->vb.i, - (unsigned long)videobuf_to_dma_contig(&buf->vb), - (unsigned long)ioread32be(&vr->field_base_addr)); - - if (waitqueue_active(&buf->vb.done)) { - list_del(&buf->vb.queue); - buf->vb.ts = ktime_get_ns(); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - wake_up(&buf->vb.done); - } - /* activate next dma buffer */ - viu_activate_next_buf(dev, vidq); - } -} - -static irqreturn_t viu_intr(int irq, void *dev_id) -{ - struct viu_dev *dev = (struct viu_dev *)dev_id; - struct viu_reg __iomem *vr = dev->vr; - u32 status; - u32 error; - - status = ioread32be(&vr->status_cfg); - - if (status & INT_ERROR_STATUS) { - dev->irqs.error_irq++; - error = status & ERR_MASK; - if (error) - dprintk(1, "Err: error(%d), times:%d!\n", - error >> 4, dev->irqs.error_irq); - /* Clear interrupt error bit and error flags */ - iowrite32be((status & 0xffc0ffff) | INT_ERROR_STATUS, - &vr->status_cfg); - } - - if (status & INT_DMA_END_STATUS) { - dev->irqs.dma_end_irq++; - dev->dma_done = 1; - dprintk(2, "VIU DMA end interrupt times: %d\n", - dev->irqs.dma_end_irq); - } - - if (status & INT_HSYNC_STATUS) - dev->irqs.hsync_irq++; - - if (status & INT_FIELD_STATUS) { - dev->irqs.field_irq++; - dprintk(2, "VIU field interrupt times: %d\n", - dev->irqs.field_irq); - } - - if (status & INT_VSTART_STATUS) - dev->irqs.vstart_irq++; - - if (status & INT_VSYNC_STATUS) { - dev->irqs.vsync_irq++; - dprintk(2, "VIU vsync interrupt times: %d\n", - dev->irqs.vsync_irq); - } - - /* clear all pending irqs */ - status = ioread32be(&vr->status_cfg); - iowrite32be((status & 0xffc0ffff) | (status & INT_ALL_STATUS), - &vr->status_cfg); - - if (dev->ovenable) { - viu_overlay_intr(dev, status); - return IRQ_HANDLED; - } - - /* Capture mode */ - viu_capture_intr(dev, status); - return IRQ_HANDLED; -} - -/* - * File operations for the device - */ -static int viu_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct viu_dev *dev = video_get_drvdata(vdev); - struct viu_fh *fh; - struct viu_reg __iomem *vr; - int minor = vdev->minor; - u32 status_cfg; - - dprintk(1, "viu: open (minor=%d)\n", minor); - - dev->users++; - if (dev->users > 1) { - dev->users--; - return -EBUSY; - } - - vr = dev->vr; - - dprintk(1, "open minor=%d type=%s users=%d\n", minor, - v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); - - if (mutex_lock_interruptible(&dev->lock)) { - dev->users--; - return -ERESTARTSYS; - } - - /* allocate and initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) { - dev->users--; - mutex_unlock(&dev->lock); - return -ENOMEM; - } - - v4l2_fh_init(&fh->fh, vdev); - file->private_data = fh; - fh->dev = dev; - - fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32); - fh->width = norm_maxw(); - fh->height = norm_maxh(); - dev->crop_current.width = fh->width; - dev->crop_current.height = fh->height; - - dprintk(1, "Open: fh=%p, dev=%p, dev->vidq=%p\n", fh, dev, &dev->vidq); - dprintk(1, "Open: list_empty queued=%d\n", - list_empty(&dev->vidq.queued)); - dprintk(1, "Open: list_empty active=%d\n", - list_empty(&dev->vidq.active)); - - viu_default_settings(vr); - - status_cfg = ioread32be(&vr->status_cfg); - iowrite32be(status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN | - INT_FIELD_EN | INT_VSTART_EN | - INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN), - &vr->status_cfg); - - status_cfg = ioread32be(&vr->status_cfg); - iowrite32be(status_cfg | INT_ALL_STATUS, &vr->status_cfg); - - spin_lock_init(&fh->vbq_lock); - videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops, - dev->dev, &fh->vbq_lock, - fh->type, V4L2_FIELD_INTERLACED, - sizeof(struct viu_buf), fh, - &fh->dev->lock); - v4l2_fh_add(&fh->fh); - mutex_unlock(&dev->lock); - return 0; -} - -static ssize_t viu_read(struct file *file, char __user *data, size_t count, - loff_t *ppos) -{ - struct viu_fh *fh = file->private_data; - struct viu_dev *dev = fh->dev; - int ret = 0; - - dprintk(2, "%s\n", __func__); - if (dev->ovenable) - dev->ovenable = 0; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - viu_start_dma(dev); - ret = videobuf_read_stream(&fh->vb_vidq, data, count, - ppos, 0, file->f_flags & O_NONBLOCK); - mutex_unlock(&dev->lock); - return ret; - } - return 0; -} - -static __poll_t viu_poll(struct file *file, struct poll_table_struct *wait) -{ - struct viu_fh *fh = file->private_data; - struct videobuf_queue *q = &fh->vb_vidq; - struct viu_dev *dev = fh->dev; - __poll_t req_events = poll_requested_events(wait); - __poll_t res = v4l2_ctrl_poll(file, wait); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return EPOLLERR; - - if (!(req_events & (EPOLLIN | EPOLLRDNORM))) - return res; - - mutex_lock(&dev->lock); - res |= videobuf_poll_stream(file, q, wait); - mutex_unlock(&dev->lock); - return res; -} - -static int viu_release(struct file *file) -{ - struct viu_fh *fh = file->private_data; - struct viu_dev *dev = fh->dev; - int minor = video_devdata(file)->minor; - - mutex_lock(&dev->lock); - viu_stop_dma(dev); - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - mutex_unlock(&dev->lock); - - kfree(fh); - - dev->users--; - dprintk(1, "close (minor=%d, users=%d)\n", - minor, dev->users); - return 0; -} - -static void viu_reset(struct viu_reg __iomem *reg) -{ - iowrite32be(0, ®->status_cfg); - iowrite32be(0x9512a254, ®->luminance); - iowrite32be(0x03310000, ®->chroma_r); - iowrite32be(0x06600f38, ®->chroma_g); - iowrite32be(0x00000409, ®->chroma_b); - iowrite32be(0, ®->field_base_addr); - iowrite32be(0, ®->dma_inc); - iowrite32be(0x01e002d0, ®->picture_count); - iowrite32be(0x00000090, ®->req_alarm); - iowrite32be(0x000000ff, ®->alpha); -} - -static int viu_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct viu_fh *fh = file->private_data; - struct viu_dev *dev = fh->dev; - int ret; - - dprintk(1, "mmap called, vma=%p\n", vma); - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - mutex_unlock(&dev->lock); - - dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, - ret); - - return ret; -} - -static const struct v4l2_file_operations viu_fops = { - .owner = THIS_MODULE, - .open = viu_open, - .release = viu_release, - .read = viu_read, - .poll = viu_poll, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = viu_mmap, -}; - -static const struct v4l2_ioctl_ops viu_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap, - .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt, - .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay, - .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay, - .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay, - .vidioc_overlay = vidioc_overlay, - .vidioc_g_fbuf = vidioc_g_fbuf, - .vidioc_s_fbuf = vidioc_s_fbuf, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_g_std = vidioc_g_std, - .vidioc_s_std = vidioc_s_std, - .vidioc_querystd = vidioc_querystd, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static const struct video_device viu_template = { - .name = "FSL viu", - .fops = &viu_fops, - .minor = -1, - .ioctl_ops = &viu_ioctl_ops, - .release = video_device_release, - - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, - .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE, -}; - -static int viu_of_probe(struct platform_device *op) -{ - struct viu_dev *viu_dev; - struct video_device *vdev; - struct resource r; - struct viu_reg __iomem *viu_regs; - struct i2c_adapter *ad; - int ret, viu_irq; - struct clk *clk; - - ret = of_address_to_resource(op->dev.of_node, 0, &r); - if (ret) { - dev_err(&op->dev, "Can't parse device node resource\n"); - return -ENODEV; - } - - viu_irq = irq_of_parse_and_map(op->dev.of_node, 0); - if (!viu_irq) { - dev_err(&op->dev, "Error while mapping the irq\n"); - return -EINVAL; - } - - /* request mem region */ - if (!devm_request_mem_region(&op->dev, r.start, - sizeof(struct viu_reg), DRV_NAME)) { - dev_err(&op->dev, "Error while requesting mem region\n"); - ret = -EBUSY; - goto err_irq; - } - - /* remap registers */ - viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg)); - if (!viu_regs) { - dev_err(&op->dev, "Can't map register set\n"); - ret = -ENOMEM; - goto err_irq; - } - - /* Prepare our private structure */ - viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_KERNEL); - if (!viu_dev) { - dev_err(&op->dev, "Can't allocate private structure\n"); - ret = -ENOMEM; - goto err_irq; - } - - viu_dev->vr = viu_regs; - viu_dev->irq = viu_irq; - viu_dev->dev = &op->dev; - - /* init video dma queues */ - INIT_LIST_HEAD(&viu_dev->vidq.active); - INIT_LIST_HEAD(&viu_dev->vidq.queued); - - snprintf(viu_dev->v4l2_dev.name, - sizeof(viu_dev->v4l2_dev.name), "%s", "VIU"); - ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev); - if (ret < 0) { - dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret); - goto err_irq; - } - - ad = i2c_get_adapter(0); - if (!ad) { - ret = -EFAULT; - dev_err(&op->dev, "couldn't get i2c adapter\n"); - goto err_v4l2; - } - - v4l2_ctrl_handler_init(&viu_dev->hdl, 5); - if (viu_dev->hdl.error) { - ret = viu_dev->hdl.error; - dev_err(&op->dev, "couldn't register control\n"); - goto err_i2c; - } - /* This control handler will inherit the control(s) from the - sub-device(s). */ - viu_dev->v4l2_dev.ctrl_handler = &viu_dev->hdl; - viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad, - "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); - - timer_setup(&viu_dev->vidq.timeout, viu_vid_timeout, 0); - viu_dev->std = V4L2_STD_NTSC_M; - viu_dev->first = 1; - - /* Allocate memory for video device */ - vdev = video_device_alloc(); - if (vdev == NULL) { - ret = -ENOMEM; - goto err_hdl; - } - - *vdev = viu_template; - - vdev->v4l2_dev = &viu_dev->v4l2_dev; - - viu_dev->vdev = vdev; - - /* initialize locks */ - mutex_init(&viu_dev->lock); - viu_dev->vdev->lock = &viu_dev->lock; - spin_lock_init(&viu_dev->slock); - - video_set_drvdata(viu_dev->vdev, viu_dev); - - mutex_lock(&viu_dev->lock); - - ret = video_register_device(viu_dev->vdev, VFL_TYPE_VIDEO, -1); - if (ret < 0) { - video_device_release(viu_dev->vdev); - goto err_unlock; - } - - /* enable VIU clock */ - clk = devm_clk_get(&op->dev, "ipg"); - if (IS_ERR(clk)) { - dev_err(&op->dev, "failed to lookup the clock!\n"); - ret = PTR_ERR(clk); - goto err_vdev; - } - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(&op->dev, "failed to enable the clock!\n"); - goto err_vdev; - } - viu_dev->clk = clk; - - /* reset VIU module */ - viu_reset(viu_dev->vr); - - /* install interrupt handler */ - if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) { - dev_err(&op->dev, "Request VIU IRQ failed.\n"); - ret = -ENODEV; - goto err_clk; - } - - mutex_unlock(&viu_dev->lock); - - dev_info(&op->dev, "Freescale VIU Video Capture Board\n"); - return ret; - -err_clk: - clk_disable_unprepare(viu_dev->clk); -err_vdev: - video_unregister_device(viu_dev->vdev); -err_unlock: - mutex_unlock(&viu_dev->lock); -err_hdl: - v4l2_ctrl_handler_free(&viu_dev->hdl); -err_i2c: - i2c_put_adapter(ad); -err_v4l2: - v4l2_device_unregister(&viu_dev->v4l2_dev); -err_irq: - irq_dispose_mapping(viu_irq); - return ret; -} - -static int viu_of_remove(struct platform_device *op) -{ - struct v4l2_device *v4l2_dev = platform_get_drvdata(op); - struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); - struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next, - struct v4l2_subdev, list); - struct i2c_client *client = v4l2_get_subdevdata(sdev); - - free_irq(dev->irq, (void *)dev); - irq_dispose_mapping(dev->irq); - - clk_disable_unprepare(dev->clk); - - v4l2_ctrl_handler_free(&dev->hdl); - video_unregister_device(dev->vdev); - i2c_put_adapter(client->adapter); - v4l2_device_unregister(&dev->v4l2_dev); - return 0; -} - -#ifdef CONFIG_PM -static int viu_suspend(struct platform_device *op, pm_message_t state) -{ - struct v4l2_device *v4l2_dev = platform_get_drvdata(op); - struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); - - clk_disable(dev->clk); - return 0; -} - -static int viu_resume(struct platform_device *op) -{ - struct v4l2_device *v4l2_dev = platform_get_drvdata(op); - struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); - - clk_enable(dev->clk); - return 0; -} -#endif - -/* - * Initialization and module stuff - */ -static const struct of_device_id mpc512x_viu_of_match[] = { - { - .compatible = "fsl,mpc5121-viu", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match); - -static struct platform_driver viu_of_platform_driver = { - .probe = viu_of_probe, - .remove = viu_of_remove, -#ifdef CONFIG_PM - .suspend = viu_suspend, - .resume = viu_resume, -#endif - .driver = { - .name = DRV_NAME, - .of_match_table = mpc512x_viu_of_match, - }, -}; - -module_platform_driver(viu_of_platform_driver); - -MODULE_DESCRIPTION("Freescale Video-In(VIU)"); -MODULE_AUTHOR("Hongjun Chen"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(VIU_VERSION); diff --git a/drivers/staging/media/deprecated/meye/Kconfig b/drivers/staging/media/deprecated/meye/Kconfig deleted file mode 100644 index f135f8568c85..000000000000 --- a/drivers/staging/media/deprecated/meye/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_MEYE - tristate "Sony Vaio Picturebook Motion Eye Video For Linux (DEPRECATED)" - depends on PCI && VIDEO_DEV - depends on SONY_LAPTOP - depends on X86 || COMPILE_TEST - help - This is the video4linux driver for the Motion Eye camera found - in the Vaio Picturebook laptops. Please read the material in - <file:Documentation/admin-guide/media/meye.rst> for more information. - - If you say Y or M here, you need to say Y or M to "Sony Laptop - Extras" in the misc device section. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here: the - module will be called meye. diff --git a/drivers/staging/media/deprecated/meye/Makefile b/drivers/staging/media/deprecated/meye/Makefile deleted file mode 100644 index 36f1f86f0d58..000000000000 --- a/drivers/staging/media/deprecated/meye/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_MEYE) += meye.o diff --git a/drivers/staging/media/deprecated/meye/TODO b/drivers/staging/media/deprecated/meye/TODO deleted file mode 100644 index 6d1d1433d5a0..000000000000 --- a/drivers/staging/media/deprecated/meye/TODO +++ /dev/null @@ -1,6 +0,0 @@ -The meye driver does not use the vb2 framework for streaming -video, instead it implements this in the driver. - -To prevent removal of this driver early 2023 it has to be -converted to use vb2. Contact the linux-media@vger.kernel.org -mailing list if you want to do this. diff --git a/drivers/staging/media/deprecated/meye/meye.c b/drivers/staging/media/deprecated/meye/meye.c deleted file mode 100644 index 746c6ea1c0a7..000000000000 --- a/drivers/staging/media/deprecated/meye/meye.c +++ /dev/null @@ -1,1814 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net> - * - * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com> - * - * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - */ -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/gfp.h> -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-fh.h> -#include <media/v4l2-event.h> -#include <linux/uaccess.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/vmalloc.h> -#include <linux/dma-mapping.h> - -#include "meye.h" -#include <linux/meye.h> - -MODULE_AUTHOR("Stelian Pop <stelian@popies.net>"); -MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MEYE_DRIVER_VERSION); - -/* number of grab buffers */ -static unsigned int gbuffers = 2; -module_param(gbuffers, int, 0444); -MODULE_PARM_DESC(gbuffers, "number of capture buffers, default is 2 (32 max)"); - -/* size of a grab buffer */ -static unsigned int gbufsize = MEYE_MAX_BUFSIZE; -module_param(gbufsize, int, 0444); -MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400 (will be rounded up to a page multiple)"); - -/* /dev/videoX registration number */ -static int video_nr = -1; -module_param(video_nr, int, 0444); -MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)"); - -/* driver structure - only one possible */ -static struct meye meye; - -/****************************************************************************/ -/* Memory allocation routines (stolen from bttv-driver.c) */ -/****************************************************************************/ -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (mem) { - memset(mem, 0, size); - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) { - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); - } -} - -/* - * return a page table pointing to N pages of locked memory - * - * NOTE: The meye device expects DMA addresses on 32 bits, we build - * a table of 1024 entries = 4 bytes * 1024 = 4096 bytes. - */ -static int ptable_alloc(void) -{ - u32 *pt; - int i; - - memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - - /* give only 32 bit DMA addresses */ - if (dma_set_mask(&meye.mchip_dev->dev, DMA_BIT_MASK(32))) - return -1; - - meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - &meye.mchip_dmahandle, - GFP_KERNEL); - if (!meye.mchip_ptable_toc) { - meye.mchip_dmahandle = 0; - return -1; - } - - pt = meye.mchip_ptable_toc; - for (i = 0; i < MCHIP_NB_PAGES; i++) { - dma_addr_t dma; - meye.mchip_ptable[i] = dma_alloc_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - &dma, - GFP_KERNEL); - if (!meye.mchip_ptable[i]) { - int j; - pt = meye.mchip_ptable_toc; - for (j = 0; j < i; ++j) { - dma = (dma_addr_t) *pt; - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable[j], dma); - pt++; - } - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable_toc, - meye.mchip_dmahandle); - meye.mchip_ptable_toc = NULL; - meye.mchip_dmahandle = 0; - return -1; - } - *pt = (u32) dma; - pt++; - } - return 0; -} - -static void ptable_free(void) -{ - u32 *pt; - int i; - - pt = meye.mchip_ptable_toc; - for (i = 0; i < MCHIP_NB_PAGES; i++) { - dma_addr_t dma = (dma_addr_t) *pt; - if (meye.mchip_ptable[i]) - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable[i], dma); - pt++; - } - - if (meye.mchip_ptable_toc) - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable_toc, - meye.mchip_dmahandle); - - memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - meye.mchip_ptable_toc = NULL; - meye.mchip_dmahandle = 0; -} - -/* copy data from ptable into buf */ -static void ptable_copy(u8 *buf, int start, int size, int pt_pages) -{ - int i; - - for (i = 0; i < (size / PAGE_SIZE) * PAGE_SIZE; i += PAGE_SIZE) { - memcpy(buf + i, meye.mchip_ptable[start++], PAGE_SIZE); - if (start >= pt_pages) - start = 0; - } - memcpy(buf + i, meye.mchip_ptable[start], size % PAGE_SIZE); -} - -/****************************************************************************/ -/* JPEG tables at different qualities to load into the VRJ chip */ -/****************************************************************************/ - -/* return a set of quantisation tables based on a quality from 1 to 10 */ -static u16 *jpeg_quantisation_tables(int *length, int quality) -{ - static u16 jpeg_tables[][70] = { { - 0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - 0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - }, - { - 0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46, - 0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - 0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - }, - { - 0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23, - 0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164, - 0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad, - 0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff, - 0xe6ff, 0xfffd, 0xfff8, - 0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876, - 0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xfff8, - }, - { - 0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17, - 0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042, - 0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73, - 0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba, - 0x99c7, 0xaba8, 0xffa4, - 0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e, - 0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xffa4, - }, - { - 0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712, - 0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932, - 0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556, - 0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c, - 0x7396, 0x817e, 0xff7c, - 0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b, - 0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0xff7c, - }, - { - 0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e, - 0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28, - 0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745, - 0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470, - 0x5c78, 0x6765, 0xff63, - 0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f, - 0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0xff63, - }, - { - 0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b, - 0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20, - 0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37, - 0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a, - 0x4a60, 0x5251, 0xff4f, - 0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26, - 0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0xff4f, - }, - { - 0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08, - 0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318, - 0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129, - 0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43, - 0x3748, 0x3e3d, 0xff3b, - 0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c, - 0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0xff3b, - }, - { - 0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706, - 0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710, - 0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c, - 0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d, - 0x2530, 0x2928, 0xff28, - 0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813, - 0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0xff28, - }, - { - 0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403, - 0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08, - 0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e, - 0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416, - 0x1218, 0x1514, 0xff14, - 0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409, - 0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0xff14, - }, - { - 0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0xff01, - 0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0xff01, - } }; - - if (quality < 0 || quality > 10) { - printk(KERN_WARNING - "meye: invalid quality level %d - using 8\n", quality); - quality = 8; - } - - *length = ARRAY_SIZE(jpeg_tables[quality]); - return jpeg_tables[quality]; -} - -/* return a generic set of huffman tables */ -static u16 *jpeg_huffman_tables(int *length) -{ - static u16 tables[] = { - 0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405, - 0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131, - 0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142, - 0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918, - 0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443, - 0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463, - 0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483, - 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A, - 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8, - 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6, - 0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2, - 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, - 0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405, - 0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206, - 0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1, - 0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125, - 0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A, - 0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A, - 0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A, - 0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, - 0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, - 0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, - 0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2, - 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, - 0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, - 0xFF0B, - 0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, - 0xFF0B - }; - - *length = ARRAY_SIZE(tables); - return tables; -} - -/****************************************************************************/ -/* MCHIP low-level functions */ -/****************************************************************************/ - -/* returns the horizontal capture size */ -static inline int mchip_hsize(void) -{ - return meye.params.subsample ? 320 : 640; -} - -/* returns the vertical capture size */ -static inline int mchip_vsize(void) -{ - return meye.params.subsample ? 240 : 480; -} - -/* waits for a register to be available */ -static void mchip_sync(int reg) -{ - u32 status; - int i; - - if (reg == MCHIP_MM_FIFO_DATA) { - for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { - status = readl(meye.mchip_mmregs + - MCHIP_MM_FIFO_STATUS); - if (!(status & MCHIP_MM_FIFO_WAIT)) { - printk(KERN_WARNING "meye: fifo not ready\n"); - return; - } - if (status & MCHIP_MM_FIFO_READY) - return; - udelay(1); - } - } else if (reg > 0x80) { - u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY - : MCHIP_HIC_STATUS_VRJ_RDY; - for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { - status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS); - if (status & mask) - return; - udelay(1); - } - } else - return; - printk(KERN_WARNING - "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n", - reg, status); -} - -/* sets a value into the register */ -static inline void mchip_set(int reg, u32 v) -{ - mchip_sync(reg); - writel(v, meye.mchip_mmregs + reg); -} - -/* get the register value */ -static inline u32 mchip_read(int reg) -{ - mchip_sync(reg); - return readl(meye.mchip_mmregs + reg); -} - -/* wait for a register to become a particular value */ -static inline int mchip_delay(u32 reg, u32 v) -{ - int n = 10; - while (--n && mchip_read(reg) != v) - udelay(1); - return n; -} - -/* setup subsampling */ -static void mchip_subsample(void) -{ - mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample); - mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize()); - mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize()); - mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize()); - mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize()); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); -} - -/* set the framerate into the mchip */ -static void mchip_set_framerate(void) -{ - mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate); -} - -/* load some huffman and quantisation tables into the VRJ chip ready - for JPEG compression */ -static void mchip_load_tables(void) -{ - int i; - int length; - u16 *tables; - - tables = jpeg_huffman_tables(&length); - for (i = 0; i < length; i++) - writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); - - tables = jpeg_quantisation_tables(&length, meye.params.quality); - for (i = 0; i < length; i++) - writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); -} - -/* setup the VRJ parameters in the chip */ -static void mchip_vrj_setup(u8 mode) -{ - mchip_set(MCHIP_VRJ_BUS_MODE, 5); - mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f); - mchip_set(MCHIP_VRJ_PDAT_USE, 1); - mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0); - mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode); - mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize()); - mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize()); - mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b); - mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF); - mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF); - mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC); - mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0); - mchip_set(MCHIP_VRJ_SOF1, 0x601); - mchip_set(MCHIP_VRJ_SOF2, 0x1502); - mchip_set(MCHIP_VRJ_SOF3, 0x1503); - mchip_set(MCHIP_VRJ_SOF4, 0x1596); - mchip_set(MCHIP_VRJ_SOS, 0x0ed0); - - mchip_load_tables(); -} - -/* sets the DMA parameters into the chip */ -static void mchip_dma_setup(dma_addr_t dma_addr) -{ - int i; - - mchip_set(MCHIP_MM_PT_ADDR, (u32)dma_addr); - for (i = 0; i < 4; i++) - mchip_set(MCHIP_MM_FIR(i), 0); - meye.mchip_fnum = 0; -} - -/* setup for DMA transfers - also zeros the framebuffer */ -static int mchip_dma_alloc(void) -{ - if (!meye.mchip_dmahandle) - if (ptable_alloc()) - return -1; - return 0; -} - -/* frees the DMA buffer */ -static void mchip_dma_free(void) -{ - if (meye.mchip_dmahandle) { - mchip_dma_setup(0); - ptable_free(); - } -} - -/* stop any existing HIC action and wait for any dma to complete then - reset the dma engine */ -static void mchip_hic_stop(void) -{ - int i, j; - - meye.mchip_mode = MCHIP_HIC_MODE_NOOP; - if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY)) - return; - for (i = 0; i < 20; ++i) { - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); - mchip_delay(MCHIP_HIC_CMD, 0); - for (j = 0; j < 100; ++j) { - if (mchip_delay(MCHIP_HIC_STATUS, - MCHIP_HIC_STATUS_IDLE)) - return; - msleep(1); - } - printk(KERN_ERR "meye: need to reset HIC!\n"); - - mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET); - msleep(250); - } - printk(KERN_ERR "meye: resetting HIC hanged!\n"); -} - -/****************************************************************************/ -/* MCHIP frame processing functions */ -/****************************************************************************/ - -/* get the next ready frame from the dma engine */ -static u32 mchip_get_frame(void) -{ - return mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); -} - -/* frees the current frame from the dma engine */ -static void mchip_free_frame(void) -{ - mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0); - meye.mchip_fnum++; - meye.mchip_fnum %= 4; -} - -/* read one frame from the framebuffer assuming it was captured using - a uncompressed transfer */ -static void mchip_cont_read_frame(u32 v, u8 *buf, int size) -{ - int pt_id; - - pt_id = (v >> 17) & 0x3FF; - - ptable_copy(buf, pt_id, size, MCHIP_NB_PAGES); -} - -/* read a compressed frame from the framebuffer */ -static int mchip_comp_read_frame(u32 v, u8 *buf, int size) -{ - int pt_start, pt_end, trailer; - int fsize; - int i; - - pt_start = (v >> 19) & 0xFF; - pt_end = (v >> 11) & 0xFF; - trailer = (v >> 1) & 0x3FF; - - if (pt_end < pt_start) - fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE + - pt_end * PAGE_SIZE + trailer * 4; - else - fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4; - - if (fsize > size) { - printk(KERN_WARNING "meye: oversized compressed frame %d\n", - fsize); - return -1; - } - - ptable_copy(buf, pt_start, fsize, MCHIP_NB_PAGES_MJPEG); - -#ifdef MEYE_JPEG_CORRECTION - - /* Some mchip generated jpeg frames are incorrect. In most - * (all ?) of those cases, the final EOI (0xff 0xd9) marker - * is not present at the end of the frame. - * - * Since adding the final marker is not enough to restore - * the jpeg integrity, we drop the frame. - */ - - for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ; - - if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9) - return -1; - -#endif - - return fsize; -} - -/* take a picture into SDRAM */ -static void mchip_take_picture(void) -{ - int i; - - mchip_hic_stop(); - mchip_subsample(); - mchip_dma_setup(meye.mchip_dmahandle); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } -} - -/* dma a previously taken picture into a buffer */ -static void mchip_get_picture(u8 *buf, int bufsize) -{ - u32 v; - int i; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } - for (i = 0; i < 4; ++i) { - v = mchip_get_frame(); - if (v & MCHIP_MM_FIR_RDY) { - mchip_cont_read_frame(v, buf, bufsize); - break; - } - mchip_free_frame(); - } -} - -/* start continuous dma capture */ -static void mchip_continuous_start(void) -{ - mchip_hic_stop(); - mchip_subsample(); - mchip_set_framerate(); - mchip_dma_setup(meye.mchip_dmahandle); - - meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); -} - -/* compress one frame into a buffer */ -static int mchip_compress_frame(u8 *buf, int bufsize) -{ - u32 v; - int len = -1, i; - - mchip_vrj_setup(0x3f); - udelay(50); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } - - for (i = 0; i < 4; ++i) { - v = mchip_get_frame(); - if (v & MCHIP_MM_FIR_RDY) { - len = mchip_comp_read_frame(v, buf, bufsize); - break; - } - mchip_free_frame(); - } - return len; -} - -#if 0 -/* uncompress one image into a buffer */ -static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize) -{ - mchip_vrj_setup(0x3f); - udelay(50); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - - return mchip_comp_read_frame(buf, bufsize); -} -#endif - -/* start continuous compressed capture */ -static void mchip_cont_compression_start(void) -{ - mchip_hic_stop(); - mchip_vrj_setup(0x3f); - mchip_subsample(); - mchip_set_framerate(); - mchip_dma_setup(meye.mchip_dmahandle); - - meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); -} - -/****************************************************************************/ -/* Interrupt handling */ -/****************************************************************************/ - -static irqreturn_t meye_irq(int irq, void *dev_id) -{ - u32 v; - int reqnr; - static int sequence; - - v = mchip_read(MCHIP_MM_INTA); - - if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT && - meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) - return IRQ_NONE; - -again: - v = mchip_get_frame(); - if (!(v & MCHIP_MM_FIR_RDY)) - return IRQ_HANDLED; - - if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { - if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, - sizeof(int), &meye.grabq_lock) != sizeof(int)) { - mchip_free_frame(); - return IRQ_HANDLED; - } - mchip_cont_read_frame(v, meye.grab_fbuffer + gbufsize * reqnr, - mchip_hsize() * mchip_vsize() * 2); - meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2; - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - meye.grab_buffer[reqnr].ts = ktime_get_ns(); - meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock); - wake_up_interruptible(&meye.proc_list); - } else { - int size; - size = mchip_comp_read_frame(v, meye.grab_temp, gbufsize); - if (size == -1) { - mchip_free_frame(); - goto again; - } - if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, - sizeof(int), &meye.grabq_lock) != sizeof(int)) { - mchip_free_frame(); - goto again; - } - memcpy(meye.grab_fbuffer + gbufsize * reqnr, meye.grab_temp, - size); - meye.grab_buffer[reqnr].size = size; - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - meye.grab_buffer[reqnr].ts = ktime_get_ns(); - meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock); - wake_up_interruptible(&meye.proc_list); - } - mchip_free_frame(); - goto again; -} - -/****************************************************************************/ -/* video4linux integration */ -/****************************************************************************/ - -static int meye_open(struct file *file) -{ - int i; - - if (test_and_set_bit(0, &meye.in_use)) - return -EBUSY; - - mchip_hic_stop(); - - if (mchip_dma_alloc()) { - printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); - clear_bit(0, &meye.in_use); - return -ENOBUFS; - } - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - kfifo_reset(&meye.grabq); - kfifo_reset(&meye.doneq); - return v4l2_fh_open(file); -} - -static int meye_release(struct file *file) -{ - mchip_hic_stop(); - mchip_dma_free(); - clear_bit(0, &meye.in_use); - return v4l2_fh_release(file); -} - -static int meyeioc_g_params(struct meye_params *p) -{ - *p = meye.params; - return 0; -} - -static int meyeioc_s_params(struct meye_params *jp) -{ - if (jp->subsample > 1) - return -EINVAL; - - if (jp->quality > 10) - return -EINVAL; - - if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) - return -EINVAL; - - if (jp->framerate > 31) - return -EINVAL; - - mutex_lock(&meye.lock); - - if (meye.params.subsample != jp->subsample || - meye.params.quality != jp->quality) - mchip_hic_stop(); /* need restart */ - - meye.params = *jp; - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, - meye.params.sharpness); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, - meye.params.agc); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, - meye.params.picture); - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_qbuf_capt(int *nb) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (*nb >= gbuffers) - return -EINVAL; - - if (*nb < 0) { - /* stop capture */ - mchip_hic_stop(); - return 0; - } - - if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - - if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) - mchip_cont_compression_start(); - - meye.grab_buffer[*nb].state = MEYE_BUF_USING; - kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), - &meye.grabq_lock); - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_sync(struct file *file, void *fh, int *i) -{ - int unused; - - if (*i < 0 || *i >= gbuffers) - return -EINVAL; - - mutex_lock(&meye.lock); - switch (meye.grab_buffer[*i].state) { - - case MEYE_BUF_UNUSED: - mutex_unlock(&meye.lock); - return -EINVAL; - case MEYE_BUF_USING: - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - if (wait_event_interruptible(meye.proc_list, - (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { - mutex_unlock(&meye.lock); - return -EINTR; - } - fallthrough; - case MEYE_BUF_DONE: - meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; - if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, - sizeof(int), &meye.doneq_lock) != sizeof(int)) - break; - } - *i = meye.grab_buffer[*i].size; - mutex_unlock(&meye.lock); - return 0; -} - -static int meyeioc_stillcapt(void) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - meye.grab_buffer[0].state = MEYE_BUF_USING; - mchip_take_picture(); - - mchip_get_picture(meye.grab_fbuffer, - mchip_hsize() * mchip_vsize() * 2); - - meye.grab_buffer[0].state = MEYE_BUF_DONE; - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_stilljcapt(int *len) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - meye.grab_buffer[0].state = MEYE_BUF_USING; - *len = -1; - - while (*len == -1) { - mchip_take_picture(); - *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); - } - - meye.grab_buffer[0].state = MEYE_BUF_DONE; - mutex_unlock(&meye.lock); - return 0; -} - -static int vidioc_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - strscpy(cap->driver, "meye", sizeof(cap->driver)); - strscpy(cap->card, "meye", sizeof(cap->card)); - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strscpy(i->name, "Camera", sizeof(i->name)); - i->type = V4L2_INPUT_TYPE_CAMERA; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) -{ - if (i != 0) - return -EINVAL; - - return 0; -} - -static int meye_s_ctrl(struct v4l2_ctrl *ctrl) -{ - mutex_lock(&meye.lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, ctrl->val); - meye.brightness = ctrl->val << 10; - break; - case V4L2_CID_HUE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAHUE, ctrl->val); - meye.hue = ctrl->val << 10; - break; - case V4L2_CID_CONTRAST: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACONTRAST, ctrl->val); - meye.contrast = ctrl->val << 10; - break; - case V4L2_CID_SATURATION: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACOLOR, ctrl->val); - meye.colour = ctrl->val << 10; - break; - case V4L2_CID_MEYE_AGC: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAAGC, ctrl->val); - meye.params.agc = ctrl->val; - break; - case V4L2_CID_SHARPNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERASHARPNESS, ctrl->val); - meye.params.sharpness = ctrl->val; - break; - case V4L2_CID_MEYE_PICTURE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAPICTURE, ctrl->val); - meye.params.picture = ctrl->val; - break; - case V4L2_CID_JPEG_COMPRESSION_QUALITY: - meye.params.quality = ctrl->val; - break; - case V4L2_CID_MEYE_FRAMERATE: - meye.params.framerate = ctrl->val; - break; - default: - mutex_unlock(&meye.lock); - return -EINVAL; - } - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - if (f->index > 1) - return -EINVAL; - - if (f->index == 0) { - /* standard YUV 422 capture */ - f->flags = 0; - f->pixelformat = V4L2_PIX_FMT_YUYV; - } else { - /* compressed MJPEG capture */ - f->pixelformat = V4L2_PIX_FMT_MJPEG; - } - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - - if (f->fmt.pix.width <= 320) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - } else { - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - } - - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - switch (meye.mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - default: - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - break; - case MCHIP_HIC_MODE_CONT_COMP: - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; - break; - } - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = mchip_hsize(); - f->fmt.pix.height = mchip_vsize(); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - mutex_lock(&meye.lock); - - if (f->fmt.pix.width <= 320) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - meye.params.subsample = 1; - } else { - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - meye.params.subsample = 0; - } - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUYV: - meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; - break; - case V4L2_PIX_FMT_MJPEG: - meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; - break; - } - - mutex_unlock(&meye.lock); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) -{ - int i; - - if (req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (meye.grab_fbuffer && req->count == gbuffers) { - /* already allocated, no modifications */ - return 0; - } - - mutex_lock(&meye.lock); - if (meye.grab_fbuffer) { - for (i = 0; i < gbuffers; i++) - if (meye.vma_use_count[i]) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - rvfree(meye.grab_fbuffer, gbuffers * gbufsize); - meye.grab_fbuffer = NULL; - } - - gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS)); - req->count = gbuffers; - meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize); - - if (!meye.grab_fbuffer) { - printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); - mutex_unlock(&meye.lock); - return -ENOMEM; - } - - for (i = 0; i < gbuffers; i++) - meye.vma_use_count[i] = 0; - - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - unsigned int index = buf->index; - - if (index >= gbuffers) - return -EINVAL; - - buf->bytesused = meye.grab_buffer[index].size; - buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - - if (meye.grab_buffer[index].state == MEYE_BUF_USING) - buf->flags |= V4L2_BUF_FLAG_QUEUED; - - if (meye.grab_buffer[index].state == MEYE_BUF_DONE) - buf->flags |= V4L2_BUF_FLAG_DONE; - - buf->field = V4L2_FIELD_NONE; - v4l2_buffer_set_timestamp(buf, meye.grab_buffer[index].ts); - buf->sequence = meye.grab_buffer[index].sequence; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = index * gbufsize; - buf->length = gbufsize; - - return 0; -} - -static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (buf->index >= gbuffers) - return -EINVAL; - - if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) - return -EINVAL; - - mutex_lock(&meye.lock); - buf->flags |= V4L2_BUF_FLAG_QUEUED; - buf->flags &= ~V4L2_BUF_FLAG_DONE; - meye.grab_buffer[buf->index].state = MEYE_BUF_USING; - kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, - sizeof(int), &meye.grabq_lock); - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - int reqnr; - - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - mutex_lock(&meye.lock); - - if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - - if (wait_event_interruptible(meye.proc_list, - kfifo_len(&meye.doneq) != 0) < 0) { - mutex_unlock(&meye.lock); - return -EINTR; - } - - if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock)) { - mutex_unlock(&meye.lock); - return -EBUSY; - } - - if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - - buf->index = reqnr; - buf->bytesused = meye.grab_buffer[reqnr].size; - buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - buf->field = V4L2_FIELD_NONE; - v4l2_buffer_set_timestamp(buf, meye.grab_buffer[reqnr].ts); - buf->sequence = meye.grab_buffer[reqnr].sequence; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = reqnr * gbufsize; - buf->length = gbufsize; - meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED; - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -{ - mutex_lock(&meye.lock); - - switch (meye.mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - mchip_continuous_start(); - break; - case MCHIP_HIC_MODE_CONT_COMP: - mchip_cont_compression_start(); - break; - default: - mutex_unlock(&meye.lock); - return -EINVAL; - } - - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) -{ - mutex_lock(&meye.lock); - mchip_hic_stop(); - kfifo_reset(&meye.grabq); - kfifo_reset(&meye.doneq); - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - - mutex_unlock(&meye.lock); - return 0; -} - -static long vidioc_default(struct file *file, void *fh, bool valid_prio, - unsigned int cmd, void *arg) -{ - switch (cmd) { - case MEYEIOC_G_PARAMS: - return meyeioc_g_params((struct meye_params *) arg); - - case MEYEIOC_S_PARAMS: - return meyeioc_s_params((struct meye_params *) arg); - - case MEYEIOC_QBUF_CAPT: - return meyeioc_qbuf_capt((int *) arg); - - case MEYEIOC_SYNC: - return meyeioc_sync(file, fh, (int *) arg); - - case MEYEIOC_STILLCAPT: - return meyeioc_stillcapt(); - - case MEYEIOC_STILLJCAPT: - return meyeioc_stilljcapt((int *) arg); - - default: - return -ENOTTY; - } - -} - -static __poll_t meye_poll(struct file *file, poll_table *wait) -{ - __poll_t res = v4l2_ctrl_poll(file, wait); - - mutex_lock(&meye.lock); - poll_wait(file, &meye.proc_list, wait); - if (kfifo_len(&meye.doneq)) - res |= EPOLLIN | EPOLLRDNORM; - mutex_unlock(&meye.lock); - return res; -} - -static void meye_vm_open(struct vm_area_struct *vma) -{ - long idx = (long)vma->vm_private_data; - meye.vma_use_count[idx]++; -} - -static void meye_vm_close(struct vm_area_struct *vma) -{ - long idx = (long)vma->vm_private_data; - meye.vma_use_count[idx]--; -} - -static const struct vm_operations_struct meye_vm_ops = { - .open = meye_vm_open, - .close = meye_vm_close, -}; - -static int meye_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long page, pos; - - mutex_lock(&meye.lock); - if (size > gbuffers * gbufsize || offset > gbuffers * gbufsize - size) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - if (!meye.grab_fbuffer) { - int i; - - /* lazy allocation */ - meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize); - if (!meye.grab_fbuffer) { - printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); - mutex_unlock(&meye.lock); - return -ENOMEM; - } - for (i = 0; i < gbuffers; i++) - meye.vma_use_count[i] = 0; - } - pos = (unsigned long)meye.grab_fbuffer + offset; - - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - vma->vm_ops = &meye_vm_ops; - /* not I/O memory */ - vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_IO); - vma->vm_private_data = (void *) (offset / gbufsize); - meye_vm_open(vma); - - mutex_unlock(&meye.lock); - return 0; -} - -static const struct v4l2_file_operations meye_fops = { - .owner = THIS_MODULE, - .open = meye_open, - .release = meye_release, - .mmap = meye_mmap, - .unlocked_ioctl = video_ioctl2, - .poll = meye_poll, -}; - -static const struct v4l2_ioctl_ops meye_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - .vidioc_default = vidioc_default, -}; - -static const struct video_device meye_template = { - .name = "meye", - .fops = &meye_fops, - .ioctl_ops = &meye_ioctl_ops, - .release = video_device_release_empty, - .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, -}; - -static const struct v4l2_ctrl_ops meye_ctrl_ops = { - .s_ctrl = meye_s_ctrl, -}; - -static int __maybe_unused meye_suspend(struct device *dev) -{ - meye.pm_mchip_mode = meye.mchip_mode; - mchip_hic_stop(); - mchip_set(MCHIP_MM_INTA, 0x0); - return 0; -} - -static int __maybe_unused meye_resume(struct device *dev) -{ - pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); - - mchip_delay(MCHIP_HIC_CMD, 0); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); - msleep(1); - mchip_set(MCHIP_VRJ_SOFT_RESET, 1); - msleep(1); - mchip_set(MCHIP_MM_PCI_MODE, 5); - msleep(1); - mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - - switch (meye.pm_mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - mchip_continuous_start(); - break; - case MCHIP_HIC_MODE_CONT_COMP: - mchip_cont_compression_start(); - break; - } - return 0; -} - -static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) -{ - static const struct v4l2_ctrl_config ctrl_agc = { - .id = V4L2_CID_MEYE_AGC, - .type = V4L2_CTRL_TYPE_INTEGER, - .ops = &meye_ctrl_ops, - .name = "AGC", - .max = 63, - .step = 1, - .def = 48, - .flags = V4L2_CTRL_FLAG_SLIDER, - }; - static const struct v4l2_ctrl_config ctrl_picture = { - .id = V4L2_CID_MEYE_PICTURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .ops = &meye_ctrl_ops, - .name = "Picture", - .max = 63, - .step = 1, - }; - static const struct v4l2_ctrl_config ctrl_framerate = { - .id = V4L2_CID_MEYE_FRAMERATE, - .type = V4L2_CTRL_TYPE_INTEGER, - .ops = &meye_ctrl_ops, - .name = "Framerate", - .max = 31, - .step = 1, - }; - struct v4l2_device *v4l2_dev = &meye.v4l2_dev; - int ret = -EBUSY; - unsigned long mchip_adr; - - if (meye.mchip_dev != NULL) { - printk(KERN_ERR "meye: only one device allowed!\n"); - return ret; - } - - ret = v4l2_device_register(&pcidev->dev, v4l2_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return ret; - } - ret = -ENOMEM; - meye.mchip_dev = pcidev; - - meye.grab_temp = vmalloc(array_size(PAGE_SIZE, MCHIP_NB_PAGES_MJPEG)); - if (!meye.grab_temp) - goto outvmalloc; - - spin_lock_init(&meye.grabq_lock); - if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) - goto outkfifoalloc1; - - spin_lock_init(&meye.doneq_lock); - if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) - goto outkfifoalloc2; - - meye.vdev = meye_template; - meye.vdev.v4l2_dev = &meye.v4l2_dev; - - ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1); - if (ret) { - v4l2_err(v4l2_dev, "meye: unable to power on the camera\n"); - v4l2_err(v4l2_dev, "meye: did you enable the camera in sonypi using the module options ?\n"); - goto outsonypienable; - } - - ret = pci_enable_device(meye.mchip_dev); - if (ret) { - v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n"); - goto outenabledev; - } - - ret = -EIO; - mchip_adr = pci_resource_start(meye.mchip_dev,0); - if (!mchip_adr) { - v4l2_err(v4l2_dev, "meye: mchip has no device base address\n"); - goto outregions; - } - if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0), - "meye")) { - v4l2_err(v4l2_dev, "meye: request_mem_region failed\n"); - goto outregions; - } - meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS); - if (!meye.mchip_mmregs) { - v4l2_err(v4l2_dev, "meye: ioremap failed\n"); - goto outremap; - } - - meye.mchip_irq = pcidev->irq; - if (request_irq(meye.mchip_irq, meye_irq, - IRQF_SHARED, "meye", meye_irq)) { - v4l2_err(v4l2_dev, "request_irq failed\n"); - goto outreqirq; - } - - pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8); - pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64); - - pci_set_master(meye.mchip_dev); - - /* Ask the camera to perform a soft reset. */ - pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); - - mchip_delay(MCHIP_HIC_CMD, 0); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); - - msleep(1); - mchip_set(MCHIP_VRJ_SOFT_RESET, 1); - - msleep(1); - mchip_set(MCHIP_MM_PCI_MODE, 5); - - msleep(1); - mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - - mutex_init(&meye.lock); - init_waitqueue_head(&meye.proc_list); - - v4l2_ctrl_handler_init(&meye.hdl, 3); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 63, 1, 32); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_HUE, 0, 63, 1, 32); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_CONTRAST, 0, 63, 1, 32); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_SATURATION, 0, 63, 1, 32); - v4l2_ctrl_new_custom(&meye.hdl, &ctrl_agc, NULL); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_SHARPNESS, 0, 63, 1, 32); - v4l2_ctrl_new_custom(&meye.hdl, &ctrl_picture, NULL); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, 10, 1, 8); - v4l2_ctrl_new_custom(&meye.hdl, &ctrl_framerate, NULL); - if (meye.hdl.error) { - v4l2_err(v4l2_dev, "couldn't register controls\n"); - goto outvideoreg; - } - - v4l2_ctrl_handler_setup(&meye.hdl); - meye.vdev.ctrl_handler = &meye.hdl; - - if (video_register_device(&meye.vdev, VFL_TYPE_VIDEO, - video_nr) < 0) { - v4l2_err(v4l2_dev, "video_register_device failed\n"); - goto outvideoreg; - } - - v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n", - MEYE_DRIVER_VERSION); - v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n", - meye.mchip_dev->revision, mchip_adr, meye.mchip_irq); - - return 0; - -outvideoreg: - v4l2_ctrl_handler_free(&meye.hdl); - free_irq(meye.mchip_irq, meye_irq); -outreqirq: - iounmap(meye.mchip_mmregs); -outremap: - release_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0)); -outregions: - pci_disable_device(meye.mchip_dev); -outenabledev: - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); -outsonypienable: - kfifo_free(&meye.doneq); -outkfifoalloc2: - kfifo_free(&meye.grabq); -outkfifoalloc1: - vfree(meye.grab_temp); -outvmalloc: - return ret; -} - -static void meye_remove(struct pci_dev *pcidev) -{ - video_unregister_device(&meye.vdev); - - mchip_hic_stop(); - - mchip_dma_free(); - - /* disable interrupts */ - mchip_set(MCHIP_MM_INTA, 0x0); - - free_irq(meye.mchip_irq, meye_irq); - - iounmap(meye.mchip_mmregs); - - release_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0)); - - pci_disable_device(meye.mchip_dev); - - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - - kfifo_free(&meye.doneq); - kfifo_free(&meye.grabq); - - vfree(meye.grab_temp); - - if (meye.grab_fbuffer) { - rvfree(meye.grab_fbuffer, gbuffers*gbufsize); - meye.grab_fbuffer = NULL; - } - - printk(KERN_INFO "meye: removed\n"); -} - -static const struct pci_device_id meye_pci_tbl[] = { - { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 }, - { } -}; - -MODULE_DEVICE_TABLE(pci, meye_pci_tbl); - -static SIMPLE_DEV_PM_OPS(meye_pm_ops, meye_suspend, meye_resume); - -static struct pci_driver meye_driver = { - .name = "meye", - .id_table = meye_pci_tbl, - .probe = meye_probe, - .remove = meye_remove, - .driver.pm = &meye_pm_ops, -}; - -static int __init meye_init(void) -{ - gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS)); - if (gbufsize > MEYE_MAX_BUFSIZE) - gbufsize = MEYE_MAX_BUFSIZE; - gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) for capture\n", - gbuffers, - gbufsize / 1024, gbuffers * gbufsize / 1024); - return pci_register_driver(&meye_driver); -} - -static void __exit meye_exit(void) -{ - pci_unregister_driver(&meye_driver); -} - -module_init(meye_init); -module_exit(meye_exit); diff --git a/drivers/staging/media/deprecated/meye/meye.h b/drivers/staging/media/deprecated/meye/meye.h deleted file mode 100644 index 5fa6552cf93d..000000000000 --- a/drivers/staging/media/deprecated/meye/meye.h +++ /dev/null @@ -1,311 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net> - * - * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com> - * - * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - */ - -#ifndef _MEYE_PRIV_H_ -#define _MEYE_PRIV_H_ - -#define MEYE_DRIVER_MAJORVERSION 1 -#define MEYE_DRIVER_MINORVERSION 14 - -#define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \ - __stringify(MEYE_DRIVER_MINORVERSION) - -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kfifo.h> -#include <media/v4l2-ctrls.h> - -/****************************************************************************/ -/* Motion JPEG chip registers */ -/****************************************************************************/ - -/* Motion JPEG chip PCI configuration registers */ -#define MCHIP_PCI_POWER_CSR 0x54 -#define MCHIP_PCI_MCORE_STATUS 0x60 /* see HIC_STATUS */ -#define MCHIP_PCI_HOSTUSEREQ_SET 0x64 -#define MCHIP_PCI_HOSTUSEREQ_CLR 0x68 -#define MCHIP_PCI_LOWPOWER_SET 0x6c -#define MCHIP_PCI_LOWPOWER_CLR 0x70 -#define MCHIP_PCI_SOFTRESET_SET 0x74 - -/* Motion JPEG chip memory mapped registers */ -#define MCHIP_MM_REGS 0x200 /* 512 bytes */ -#define MCHIP_REG_TIMEOUT 1000 /* reg access, ~us */ -#define MCHIP_MCC_VRJ_TIMEOUT 1000 /* MCC & VRJ access */ - -#define MCHIP_MM_PCI_MODE 0x00 /* PCI access mode */ -#define MCHIP_MM_PCI_MODE_RETRY 0x00000001 /* retry mode */ -#define MCHIP_MM_PCI_MODE_MASTER 0x00000002 /* master access */ -#define MCHIP_MM_PCI_MODE_READ_LINE 0x00000004 /* read line */ - -#define MCHIP_MM_INTA 0x04 /* Int status/mask */ -#define MCHIP_MM_INTA_MCC 0x00000001 /* MCC interrupt */ -#define MCHIP_MM_INTA_VRJ 0x00000002 /* VRJ interrupt */ -#define MCHIP_MM_INTA_HIC_1 0x00000004 /* one frame done */ -#define MCHIP_MM_INTA_HIC_1_MASK 0x00000400 /* 1: enable */ -#define MCHIP_MM_INTA_HIC_END 0x00000008 /* all frames done */ -#define MCHIP_MM_INTA_HIC_END_MASK 0x00000800 -#define MCHIP_MM_INTA_JPEG 0x00000010 /* decompress. error */ -#define MCHIP_MM_INTA_JPEG_MASK 0x00001000 -#define MCHIP_MM_INTA_CAPTURE 0x00000020 /* capture end */ -#define MCHIP_MM_INTA_PCI_ERR 0x00000040 /* PCI error */ -#define MCHIP_MM_INTA_PCI_ERR_MASK 0x00004000 - -#define MCHIP_MM_PT_ADDR 0x08 /* page table address*/ - /* n*4kB */ -#define MCHIP_NB_PAGES 1024 /* pages for display */ -#define MCHIP_NB_PAGES_MJPEG 256 /* pages for mjpeg */ - -#define MCHIP_MM_FIR(n) (0x0c+(n)*4) /* Frame info 0-3 */ -#define MCHIP_MM_FIR_RDY 0x00000001 /* frame ready */ -#define MCHIP_MM_FIR_FAILFR_MASK 0xf8000000 /* # of failed frames */ -#define MCHIP_MM_FIR_FAILFR_SHIFT 27 - - /* continuous comp/decomp mode */ -#define MCHIP_MM_FIR_C_ENDL_MASK 0x000007fe /* end DW [10] */ -#define MCHIP_MM_FIR_C_ENDL_SHIFT 1 -#define MCHIP_MM_FIR_C_ENDP_MASK 0x0007f800 /* end page [8] */ -#define MCHIP_MM_FIR_C_ENDP_SHIFT 11 -#define MCHIP_MM_FIR_C_STARTP_MASK 0x07f80000 /* start page [8] */ -#define MCHIP_MM_FIR_C_STARTP_SHIFT 19 - - /* continuous picture output mode */ -#define MCHIP_MM_FIR_O_STARTP_MASK 0x7ffe0000 /* start page [10] */ -#define MCHIP_MM_FIR_O_STARTP_SHIFT 17 - -#define MCHIP_MM_FIFO_DATA 0x1c /* PCI TGT FIFO data */ -#define MCHIP_MM_FIFO_STATUS 0x20 /* PCI TGT FIFO stat */ -#define MCHIP_MM_FIFO_MASK 0x00000003 -#define MCHIP_MM_FIFO_WAIT_OR_READY 0x00000002 /* Bits common to WAIT & READY*/ -#define MCHIP_MM_FIFO_IDLE 0x0 /* HIC idle */ -#define MCHIP_MM_FIFO_IDLE1 0x1 /* idem ??? */ -#define MCHIP_MM_FIFO_WAIT 0x2 /* wait request */ -#define MCHIP_MM_FIFO_READY 0x3 /* data ready */ - -#define MCHIP_HIC_HOST_USEREQ 0x40 /* host uses MCORE */ - -#define MCHIP_HIC_TP_BUSY 0x44 /* taking picture */ - -#define MCHIP_HIC_PIC_SAVED 0x48 /* pic in SDRAM */ - -#define MCHIP_HIC_LOWPOWER 0x4c /* clock stopped */ - -#define MCHIP_HIC_CTL 0x50 /* HIC control */ -#define MCHIP_HIC_CTL_SOFT_RESET 0x00000001 /* MCORE reset */ -#define MCHIP_HIC_CTL_MCORE_RDY 0x00000002 /* MCORE ready */ - -#define MCHIP_HIC_CMD 0x54 /* HIC command */ -#define MCHIP_HIC_CMD_BITS 0x00000003 /* cmd width=[1:0]*/ -#define MCHIP_HIC_CMD_NOOP 0x0 -#define MCHIP_HIC_CMD_START 0x1 -#define MCHIP_HIC_CMD_STOP 0x2 - -#define MCHIP_HIC_MODE 0x58 -#define MCHIP_HIC_MODE_NOOP 0x0 -#define MCHIP_HIC_MODE_STILL_CAP 0x1 /* still pic capt */ -#define MCHIP_HIC_MODE_DISPLAY 0x2 /* display */ -#define MCHIP_HIC_MODE_STILL_COMP 0x3 /* still pic comp. */ -#define MCHIP_HIC_MODE_STILL_DECOMP 0x4 /* still pic decomp. */ -#define MCHIP_HIC_MODE_CONT_COMP 0x5 /* cont capt+comp */ -#define MCHIP_HIC_MODE_CONT_DECOMP 0x6 /* cont decomp+disp */ -#define MCHIP_HIC_MODE_STILL_OUT 0x7 /* still pic output */ -#define MCHIP_HIC_MODE_CONT_OUT 0x8 /* cont output */ - -#define MCHIP_HIC_STATUS 0x5c -#define MCHIP_HIC_STATUS_MCC_RDY 0x00000001 /* MCC reg acc ok */ -#define MCHIP_HIC_STATUS_VRJ_RDY 0x00000002 /* VRJ reg acc ok */ -#define MCHIP_HIC_STATUS_IDLE 0x00000003 -#define MCHIP_HIC_STATUS_CAPDIS 0x00000004 /* cap/disp in prog */ -#define MCHIP_HIC_STATUS_COMPDEC 0x00000008 /* (de)comp in prog */ -#define MCHIP_HIC_STATUS_BUSY 0x00000010 /* HIC busy */ - -#define MCHIP_HIC_S_RATE 0x60 /* MJPEG # frames */ - -#define MCHIP_HIC_PCI_VFMT 0x64 /* video format */ -#define MCHIP_HIC_PCI_VFMT_YVYU 0x00000001 /* 0: V Y' U Y */ - /* 1: Y' V Y U */ - -#define MCHIP_MCC_CMD 0x80 /* MCC commands */ -#define MCHIP_MCC_CMD_INITIAL 0x0 /* idle ? */ -#define MCHIP_MCC_CMD_IIC_START_SET 0x1 -#define MCHIP_MCC_CMD_IIC_END_SET 0x2 -#define MCHIP_MCC_CMD_FM_WRITE 0x3 /* frame memory */ -#define MCHIP_MCC_CMD_FM_READ 0x4 -#define MCHIP_MCC_CMD_FM_STOP 0x5 -#define MCHIP_MCC_CMD_CAPTURE 0x6 -#define MCHIP_MCC_CMD_DISPLAY 0x7 -#define MCHIP_MCC_CMD_END_DISP 0x8 -#define MCHIP_MCC_CMD_STILL_COMP 0x9 -#define MCHIP_MCC_CMD_STILL_DECOMP 0xa -#define MCHIP_MCC_CMD_STILL_OUTPUT 0xb -#define MCHIP_MCC_CMD_CONT_OUTPUT 0xc -#define MCHIP_MCC_CMD_CONT_COMP 0xd -#define MCHIP_MCC_CMD_CONT_DECOMP 0xe -#define MCHIP_MCC_CMD_RESET 0xf /* MCC reset */ - -#define MCHIP_MCC_IIC_WR 0x84 - -#define MCHIP_MCC_MCC_WR 0x88 - -#define MCHIP_MCC_MCC_RD 0x8c - -#define MCHIP_MCC_STATUS 0x90 -#define MCHIP_MCC_STATUS_CAPT 0x00000001 /* capturing */ -#define MCHIP_MCC_STATUS_DISP 0x00000002 /* displaying */ -#define MCHIP_MCC_STATUS_COMP 0x00000004 /* compressing */ -#define MCHIP_MCC_STATUS_DECOMP 0x00000008 /* decompressing */ -#define MCHIP_MCC_STATUS_MCC_WR 0x00000010 /* register ready */ -#define MCHIP_MCC_STATUS_MCC_RD 0x00000020 /* register ready */ -#define MCHIP_MCC_STATUS_IIC_WR 0x00000040 /* register ready */ -#define MCHIP_MCC_STATUS_OUTPUT 0x00000080 /* output in prog */ - -#define MCHIP_MCC_SIG_POLARITY 0x94 -#define MCHIP_MCC_SIG_POL_VS_H 0x00000001 /* VS active-high */ -#define MCHIP_MCC_SIG_POL_HS_H 0x00000002 /* HS active-high */ -#define MCHIP_MCC_SIG_POL_DOE_H 0x00000004 /* DOE active-high */ - -#define MCHIP_MCC_IRQ 0x98 -#define MCHIP_MCC_IRQ_CAPDIS_STRT 0x00000001 /* cap/disp started */ -#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK 0x00000010 -#define MCHIP_MCC_IRQ_CAPDIS_END 0x00000002 /* cap/disp ended */ -#define MCHIP_MCC_IRQ_CAPDIS_END_MASK 0x00000020 -#define MCHIP_MCC_IRQ_COMPDEC_STRT 0x00000004 /* (de)comp started */ -#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK 0x00000040 -#define MCHIP_MCC_IRQ_COMPDEC_END 0x00000008 /* (de)comp ended */ -#define MCHIP_MCC_IRQ_COMPDEC_END_MASK 0x00000080 - -#define MCHIP_MCC_HSTART 0x9c /* video in */ -#define MCHIP_MCC_VSTART 0xa0 -#define MCHIP_MCC_HCOUNT 0xa4 -#define MCHIP_MCC_VCOUNT 0xa8 -#define MCHIP_MCC_R_XBASE 0xac /* capt/disp */ -#define MCHIP_MCC_R_YBASE 0xb0 -#define MCHIP_MCC_R_XRANGE 0xb4 -#define MCHIP_MCC_R_YRANGE 0xb8 -#define MCHIP_MCC_B_XBASE 0xbc /* comp/decomp */ -#define MCHIP_MCC_B_YBASE 0xc0 -#define MCHIP_MCC_B_XRANGE 0xc4 -#define MCHIP_MCC_B_YRANGE 0xc8 - -#define MCHIP_MCC_R_SAMPLING 0xcc /* 1: 1:4 */ - -#define MCHIP_VRJ_CMD 0x100 /* VRJ commands */ - -/* VRJ registers (see table 12.2.4) */ -#define MCHIP_VRJ_COMPRESSED_DATA 0x1b0 -#define MCHIP_VRJ_PIXEL_DATA 0x1b8 - -#define MCHIP_VRJ_BUS_MODE 0x100 -#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL 0x108 -#define MCHIP_VRJ_PDAT_USE 0x110 -#define MCHIP_VRJ_MODE_SPECIFY 0x118 -#define MCHIP_VRJ_LIMIT_COMPRESSED_LO 0x120 -#define MCHIP_VRJ_LIMIT_COMPRESSED_HI 0x124 -#define MCHIP_VRJ_COMP_DATA_FORMAT 0x128 -#define MCHIP_VRJ_TABLE_DATA 0x140 -#define MCHIP_VRJ_RESTART_INTERVAL 0x148 -#define MCHIP_VRJ_NUM_LINES 0x150 -#define MCHIP_VRJ_NUM_PIXELS 0x158 -#define MCHIP_VRJ_NUM_COMPONENTS 0x160 -#define MCHIP_VRJ_SOF1 0x168 -#define MCHIP_VRJ_SOF2 0x170 -#define MCHIP_VRJ_SOF3 0x178 -#define MCHIP_VRJ_SOF4 0x180 -#define MCHIP_VRJ_SOS 0x188 -#define MCHIP_VRJ_SOFT_RESET 0x190 - -#define MCHIP_VRJ_STATUS 0x1c0 -#define MCHIP_VRJ_STATUS_BUSY 0x00001 -#define MCHIP_VRJ_STATUS_COMP_ACCESS 0x00002 -#define MCHIP_VRJ_STATUS_PIXEL_ACCESS 0x00004 -#define MCHIP_VRJ_STATUS_ERROR 0x00008 - -#define MCHIP_VRJ_IRQ_FLAG 0x1c8 -#define MCHIP_VRJ_ERROR_REPORT 0x1d8 - -#define MCHIP_VRJ_START_COMMAND 0x1a0 - -/****************************************************************************/ -/* Driver definitions. */ -/****************************************************************************/ - -/* Sony Programmable I/O Controller for accessing the camera commands */ -#include <linux/sony-laptop.h> - -/* private API definitions */ -#include <linux/meye.h> -#include <linux/mutex.h> - - -/* Enable jpg software correction */ -#define MEYE_JPEG_CORRECTION 1 - -/* Maximum size of a buffer */ -#define MEYE_MAX_BUFSIZE 614400 /* 640 * 480 * 2 */ - -/* Maximum number of buffers */ -#define MEYE_MAX_BUFNBRS 32 - -/* State of a buffer */ -#define MEYE_BUF_UNUSED 0 /* not used */ -#define MEYE_BUF_USING 1 /* currently grabbing / playing */ -#define MEYE_BUF_DONE 2 /* done */ - -/* grab buffer */ -struct meye_grab_buffer { - int state; /* state of buffer */ - unsigned long size; /* size of jpg frame */ - u64 ts; /* timestamp */ - unsigned long sequence; /* sequence number */ -}; - -/* size of kfifos containing buffer indices */ -#define MEYE_QUEUE_SIZE MEYE_MAX_BUFNBRS - -/* Motion Eye device structure */ -struct meye { - struct v4l2_device v4l2_dev; /* Main v4l2_device struct */ - struct v4l2_ctrl_handler hdl; - struct pci_dev *mchip_dev; /* pci device */ - u8 mchip_irq; /* irq */ - u8 mchip_mode; /* actual mchip mode: HIC_MODE... */ - u8 mchip_fnum; /* current mchip frame number */ - unsigned char __iomem *mchip_mmregs;/* mchip: memory mapped registers */ - u8 *mchip_ptable[MCHIP_NB_PAGES];/* mchip: ptable */ - void *mchip_ptable_toc; /* mchip: ptable toc */ - dma_addr_t mchip_dmahandle; /* mchip: dma handle to ptable toc */ - unsigned char *grab_fbuffer; /* capture framebuffer */ - unsigned char *grab_temp; /* temporary buffer */ - /* list of buffers */ - struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; - int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ - struct mutex lock; /* mutex for open/mmap... */ - struct kfifo grabq; /* queue for buffers to be grabbed */ - spinlock_t grabq_lock; /* lock protecting the queue */ - struct kfifo doneq; /* queue for grabbed buffers */ - spinlock_t doneq_lock; /* lock protecting the queue */ - wait_queue_head_t proc_list; /* wait queue */ - struct video_device vdev; /* video device parameters */ - u16 brightness; - u16 hue; - u16 contrast; - u16 colour; - struct meye_params params; /* additional parameters */ - unsigned long in_use; /* set to 1 if the device is in use */ - u8 pm_mchip_mode; /* old mchip mode */ -}; - -#endif diff --git a/drivers/staging/media/deprecated/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/Kconfig deleted file mode 100644 index 54154da79f59..000000000000 --- a/drivers/staging/media/deprecated/saa7146/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -source "drivers/staging/media/deprecated/saa7146/common/Kconfig" -source "drivers/staging/media/deprecated/saa7146/av7110/Kconfig" -source "drivers/staging/media/deprecated/saa7146/saa7146/Kconfig" -source "drivers/staging/media/deprecated/saa7146/ttpci/Kconfig" diff --git a/drivers/staging/media/deprecated/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/Makefile deleted file mode 100644 index 68e7aa10c639..000000000000 --- a/drivers/staging/media/deprecated/saa7146/Makefile +++ /dev/null @@ -1,2 +0,0 @@ - # SPDX-License-Identifier: GPL-2.0-only -obj-y += common/ av7110/ saa7146/ ttpci/ diff --git a/drivers/staging/media/deprecated/saa7146/av7110/TODO b/drivers/staging/media/deprecated/saa7146/av7110/TODO deleted file mode 100644 index 38817e04bb67..000000000000 --- a/drivers/staging/media/deprecated/saa7146/av7110/TODO +++ /dev/null @@ -1,9 +0,0 @@ -- This driver is too old and relies on a different API. - Drop it from Kernel on a couple of versions. -- Cleanup patches for the drivers here won't be accepted. - -These drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/TODO b/drivers/staging/media/deprecated/saa7146/saa7146/TODO deleted file mode 100644 index c9ae2ec79cea..000000000000 --- a/drivers/staging/media/deprecated/saa7146/saa7146/TODO +++ /dev/null @@ -1,7 +0,0 @@ -The saa7146-based drivers are one of the few drivers still not using -the vb2 framework, so these drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -In order to keep these drivers they have to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/TODO b/drivers/staging/media/deprecated/saa7146/ttpci/TODO deleted file mode 100644 index c9ae2ec79cea..000000000000 --- a/drivers/staging/media/deprecated/saa7146/ttpci/TODO +++ /dev/null @@ -1,7 +0,0 @@ -The saa7146-based drivers are one of the few drivers still not using -the vb2 framework, so these drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -In order to keep these drivers they have to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/stkwebcam/Kconfig b/drivers/staging/media/deprecated/stkwebcam/Kconfig deleted file mode 100644 index 7234498e634a..000000000000 --- a/drivers/staging/media/deprecated/stkwebcam/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_STKWEBCAM - tristate "USB Syntek DC1125 Camera support (DEPRECATED)" - depends on VIDEO_DEV - depends on MEDIA_USB_SUPPORT && MEDIA_CAMERA_SUPPORT - help - Say Y here if you want to use this type of camera. - Supported devices are typically found in some Asus laptops, - with USB id 174f:a311 and 05e1:0501. Other Syntek cameras - may be supported by the stk11xx driver, from which this is - derived, see <http://sourceforge.net/projects/syntekdriver/> - - This driver is deprecated and is scheduled for removal by - the end of 2022. See the TODO file for more information. - - To compile this driver as a module, choose M here: the - module will be called stkwebcam. - diff --git a/drivers/staging/media/deprecated/stkwebcam/Makefile b/drivers/staging/media/deprecated/stkwebcam/Makefile deleted file mode 100644 index 17ad7b6f43d0..000000000000 --- a/drivers/staging/media/deprecated/stkwebcam/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -stkwebcam-objs := stk-webcam.o stk-sensor.o - -obj-$(CONFIG_VIDEO_STKWEBCAM) += stkwebcam.o - diff --git a/drivers/staging/media/deprecated/stkwebcam/TODO b/drivers/staging/media/deprecated/stkwebcam/TODO deleted file mode 100644 index 735304a72729..000000000000 --- a/drivers/staging/media/deprecated/stkwebcam/TODO +++ /dev/null @@ -1,12 +0,0 @@ -This is a very old driver for very old hardware (specifically -laptops that use this sensor). In addition according to reports -the picture quality is quite bad. - -This is also one of the few drivers still not using the vb2 -framework (or even the old videobuf framework!), so this driver -is now deprecated with the intent of removing it altogether by -the end of 2022. - -In order to keep this driver it has to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c b/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c deleted file mode 100644 index 94aa6a27f934..000000000000 --- a/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c +++ /dev/null @@ -1,587 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams) - * - * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com> - * - * Some parts derived from ov7670.c: - * Copyright 2006 One Laptop Per Child Association, Inc. Written - * by Jonathan Corbet with substantial inspiration from Mark - * McClelland's ovcamchip code. - * - * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> - * - * This file may be distributed under the terms of the GNU General - */ - -/* Controlling the sensor via the STK1125 vendor specific control interface: - * The camera uses an OmniVision sensor and the stk1125 provides an - * SCCB(i2c)-USB bridge which let us program the sensor. - * In my case the sensor id is 0x9652, it can be read from sensor's register - * 0x0A and 0x0B as follows: - * - read register #R: - * output #R to index 0x0208 - * output 0x0070 to index 0x0200 - * input 1 byte from index 0x0201 (some kind of status register) - * until its value is 0x01 - * input 1 byte from index 0x0209. This is the value of #R - * - write value V to register #R - * output #R to index 0x0204 - * output V to index 0x0205 - * output 0x0005 to index 0x0200 - * input 1 byte from index 0x0201 until its value becomes 0x04 - */ - -/* It seems the i2c bus is controlled with these registers */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "stk-webcam.h" - -#define STK_IIC_BASE (0x0200) -# define STK_IIC_OP (STK_IIC_BASE) -# define STK_IIC_OP_TX (0x05) -# define STK_IIC_OP_RX (0x70) -# define STK_IIC_STAT (STK_IIC_BASE+1) -# define STK_IIC_STAT_TX_OK (0x04) -# define STK_IIC_STAT_RX_OK (0x01) -/* I don't know what does this register. - * when it is 0x00 or 0x01, we cannot talk to the sensor, - * other values work */ -# define STK_IIC_ENABLE (STK_IIC_BASE+2) -# define STK_IIC_ENABLE_NO (0x00) -/* This is what the driver writes in windows */ -# define STK_IIC_ENABLE_YES (0x1e) -/* - * Address of the slave. Seems like the binary driver look for the - * sensor in multiple places, attempting a reset sequence. - * We only know about the ov9650 - */ -# define STK_IIC_ADDR (STK_IIC_BASE+3) -# define STK_IIC_TX_INDEX (STK_IIC_BASE+4) -# define STK_IIC_TX_VALUE (STK_IIC_BASE+5) -# define STK_IIC_RX_INDEX (STK_IIC_BASE+8) -# define STK_IIC_RX_VALUE (STK_IIC_BASE+9) - -#define MAX_RETRIES (50) - -#define SENSOR_ADDRESS (0x60) - -/* From ov7670.c (These registers aren't fully accurate) */ - -/* Registers */ -#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ -#define REG_BLUE 0x01 /* blue gain */ -#define REG_RED 0x02 /* red gain */ -#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ -#define REG_COM1 0x04 /* Control 1 */ -#define COM1_CCIR656 0x40 /* CCIR656 enable */ -#define COM1_QFMT 0x20 /* QVGA/QCIF format */ -#define COM1_SKIP_0 0x00 /* Do not skip any row */ -#define COM1_SKIP_2 0x04 /* Skip 2 rows of 4 */ -#define COM1_SKIP_3 0x08 /* Skip 3 rows of 4 */ -#define REG_BAVE 0x05 /* U/B Average level */ -#define REG_GbAVE 0x06 /* Y/Gb Average level */ -#define REG_AECHH 0x07 /* AEC MS 5 bits */ -#define REG_RAVE 0x08 /* V/R Average level */ -#define REG_COM2 0x09 /* Control 2 */ -#define COM2_SSLEEP 0x10 /* Soft sleep mode */ -#define REG_PID 0x0a /* Product ID MSB */ -#define REG_VER 0x0b /* Product ID LSB */ -#define REG_COM3 0x0c /* Control 3 */ -#define COM3_SWAP 0x40 /* Byte swap */ -#define COM3_SCALEEN 0x08 /* Enable scaling */ -#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ -#define REG_COM4 0x0d /* Control 4 */ -#define REG_COM5 0x0e /* All "reserved" */ -#define REG_COM6 0x0f /* Control 6 */ -#define REG_AECH 0x10 /* More bits of AEC value */ -#define REG_CLKRC 0x11 /* Clock control */ -#define CLK_PLL 0x80 /* Enable internal PLL */ -#define CLK_EXT 0x40 /* Use external clock directly */ -#define CLK_SCALE 0x3f /* Mask for internal clock scale */ -#define REG_COM7 0x12 /* Control 7 */ -#define COM7_RESET 0x80 /* Register reset */ -#define COM7_FMT_MASK 0x38 -#define COM7_FMT_SXGA 0x00 -#define COM7_FMT_VGA 0x40 -#define COM7_FMT_CIF 0x20 /* CIF format */ -#define COM7_FMT_QVGA 0x10 /* QVGA format */ -#define COM7_FMT_QCIF 0x08 /* QCIF format */ -#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ -#define COM7_YUV 0x00 /* YUV */ -#define COM7_BAYER 0x01 /* Bayer format */ -#define COM7_PBAYER 0x05 /* "Processed bayer" */ -#define REG_COM8 0x13 /* Control 8 */ -#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ -#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ -#define COM8_BFILT 0x20 /* Band filter enable */ -#define COM8_AGC 0x04 /* Auto gain enable */ -#define COM8_AWB 0x02 /* White balance enable */ -#define COM8_AEC 0x01 /* Auto exposure enable */ -#define REG_COM9 0x14 /* Control 9 - gain ceiling */ -#define REG_COM10 0x15 /* Control 10 */ -#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ -#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ -#define COM10_HREF_REV 0x08 /* Reverse HREF */ -#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ -#define COM10_VS_NEG 0x02 /* VSYNC negative */ -#define COM10_HS_NEG 0x01 /* HSYNC negative */ -#define REG_HSTART 0x17 /* Horiz start high bits */ -#define REG_HSTOP 0x18 /* Horiz stop high bits */ -#define REG_VSTART 0x19 /* Vert start high bits */ -#define REG_VSTOP 0x1a /* Vert stop high bits */ -#define REG_PSHFT 0x1b /* Pixel delay after HREF */ -#define REG_MIDH 0x1c /* Manuf. ID high */ -#define REG_MIDL 0x1d /* Manuf. ID low */ -#define REG_MVFP 0x1e /* Mirror / vflip */ -#define MVFP_MIRROR 0x20 /* Mirror image */ -#define MVFP_FLIP 0x10 /* Vertical flip */ - -#define REG_AEW 0x24 /* AGC upper limit */ -#define REG_AEB 0x25 /* AGC lower limit */ -#define REG_VPT 0x26 /* AGC/AEC fast mode op region */ -#define REG_ADVFL 0x2d /* Insert dummy lines (LSB) */ -#define REG_ADVFH 0x2e /* Insert dummy lines (MSB) */ -#define REG_HSYST 0x30 /* HSYNC rising edge delay */ -#define REG_HSYEN 0x31 /* HSYNC falling edge delay */ -#define REG_HREF 0x32 /* HREF pieces */ -#define REG_TSLB 0x3a /* lots of stuff */ -#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ -#define TSLB_BYTEORD 0x08 /* swap bytes in 16bit mode? */ -#define REG_COM11 0x3b /* Control 11 */ -#define COM11_NIGHT 0x80 /* NIght mode enable */ -#define COM11_NMFR 0x60 /* Two bit NM frame rate */ -#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ -#define COM11_50HZ 0x08 /* Manual 50Hz select */ -#define COM11_EXP 0x02 -#define REG_COM12 0x3c /* Control 12 */ -#define COM12_HREF 0x80 /* HREF always */ -#define REG_COM13 0x3d /* Control 13 */ -#define COM13_GAMMA 0x80 /* Gamma enable */ -#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ -#define COM13_CMATRIX 0x10 /* Enable color matrix for RGB or YUV */ -#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ -#define REG_COM14 0x3e /* Control 14 */ -#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ -#define REG_EDGE 0x3f /* Edge enhancement factor */ -#define REG_COM15 0x40 /* Control 15 */ -#define COM15_R10F0 0x00 /* Data range 10 to F0 */ -#define COM15_R01FE 0x80 /* 01 to FE */ -#define COM15_R00FF 0xc0 /* 00 to FF */ -#define COM15_RGB565 0x10 /* RGB565 output */ -#define COM15_RGBFIXME 0x20 /* FIXME */ -#define COM15_RGB555 0x30 /* RGB555 output */ -#define REG_COM16 0x41 /* Control 16 */ -#define COM16_AWBGAIN 0x08 /* AWB gain enable */ -#define REG_COM17 0x42 /* Control 17 */ -#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ -#define COM17_CBAR 0x08 /* DSP Color bar */ - -/* - * This matrix defines how the colors are generated, must be - * tweaked to adjust hue and saturation. - * - * Order: v-red, v-green, v-blue, u-red, u-green, u-blue - * - * They are nine-bit signed quantities, with the sign bit - * stored in 0x58. Sign for v-red is bit 0, and up from there. - */ -#define REG_CMATRIX_BASE 0x4f -#define CMATRIX_LEN 6 -#define REG_CMATRIX_SIGN 0x58 - - -#define REG_BRIGHT 0x55 /* Brightness */ -#define REG_CONTRAS 0x56 /* Contrast control */ - -#define REG_GFIX 0x69 /* Fix gain control */ - -#define REG_RGB444 0x8c /* RGB 444 control */ -#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ -#define R444_RGBX 0x01 /* Empty nibble at end */ - -#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ -#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ - -#define REG_BD50MAX 0xa5 /* 50hz banding step limit */ -#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ -#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ -#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ -#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ -#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ -#define REG_BD60MAX 0xab /* 60hz banding step limit */ - - - - -/* Returns 0 if OK */ -static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) -{ - int i = 0; - u8 tmpval = 0; - - if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX)) - return 1; - do { - if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) - return 1; - i++; - } while (tmpval == 0 && i < MAX_RETRIES); - if (tmpval != STK_IIC_STAT_TX_OK) { - if (tmpval) - pr_err("stk_sensor_outb failed, status=0x%02x\n", - tmpval); - return 1; - } else - return 0; -} - -static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) -{ - int i = 0; - u8 tmpval = 0; - - if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX)) - return 1; - do { - if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) - return 1; - i++; - } while (tmpval == 0 && i < MAX_RETRIES); - if (tmpval != STK_IIC_STAT_RX_OK) { - if (tmpval) - pr_err("stk_sensor_inb failed, status=0x%02x\n", - tmpval); - return 1; - } - - if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval)) - return 1; - - *val = tmpval; - return 0; -} - -static int stk_sensor_write_regvals(struct stk_camera *dev, - struct regval *rv) -{ - int ret; - if (rv == NULL) - return 0; - while (rv->reg != 0xff || rv->val != 0xff) { - ret = stk_sensor_outb(dev, rv->reg, rv->val); - if (ret != 0) - return ret; - rv++; - } - return 0; -} - -int stk_sensor_sleep(struct stk_camera *dev) -{ - u8 tmp; - return stk_sensor_inb(dev, REG_COM2, &tmp) - || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP); -} - -int stk_sensor_wakeup(struct stk_camera *dev) -{ - u8 tmp; - return stk_sensor_inb(dev, REG_COM2, &tmp) - || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP); -} - -static struct regval ov_initvals[] = { - {REG_CLKRC, CLK_PLL}, - {REG_COM11, 0x01}, - {0x6a, 0x7d}, - {REG_AECH, 0x40}, - {REG_GAIN, 0x00}, - {REG_BLUE, 0x80}, - {REG_RED, 0x80}, - /* Do not enable fast AEC for now */ - /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/ - {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC}, - {0x39, 0x50}, {0x38, 0x93}, - {0x37, 0x00}, {0x35, 0x81}, - {REG_COM5, 0x20}, - {REG_COM1, 0x00}, - {REG_COM3, 0x00}, - {REG_COM4, 0x00}, - {REG_PSHFT, 0x00}, - {0x16, 0x07}, - {0x33, 0xe2}, {0x34, 0xbf}, - {REG_COM16, 0x00}, - {0x96, 0x04}, - /* Gamma curve values */ -/* { 0x7a, 0x20 }, { 0x7b, 0x10 }, - { 0x7c, 0x1e }, { 0x7d, 0x35 }, - { 0x7e, 0x5a }, { 0x7f, 0x69 }, - { 0x80, 0x76 }, { 0x81, 0x80 }, - { 0x82, 0x88 }, { 0x83, 0x8f }, - { 0x84, 0x96 }, { 0x85, 0xa3 }, - { 0x86, 0xaf }, { 0x87, 0xc4 }, - { 0x88, 0xd7 }, { 0x89, 0xe8 }, -*/ - {REG_GFIX, 0x40}, - {0x8e, 0x00}, - {REG_COM12, 0x73}, - {0x8f, 0xdf}, {0x8b, 0x06}, - {0x8c, 0x20}, - {0x94, 0x88}, {0x95, 0x88}, -/* {REG_COM15, 0xc1}, TODO */ - {0x29, 0x3f}, - {REG_COM6, 0x42}, - {REG_BD50MAX, 0x80}, - {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92}, - {REG_BD60MAX, 0x0a}, - {0x90, 0x00}, {0x91, 0x00}, - {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00}, - {REG_AEW, 0x68}, {REG_AEB, 0x5c}, - {REG_VPT, 0xc3}, - {REG_COM9, 0x2e}, - {0x2a, 0x00}, {0x2b, 0x00}, - - {0xff, 0xff}, /* END MARKER */ -}; - -/* Probe the I2C bus and initialise the sensor chip */ -int stk_sensor_init(struct stk_camera *dev) -{ - u8 idl = 0; - u8 idh = 0; - - if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES) - || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS) - || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) { - pr_err("Sensor resetting failed\n"); - return -ENODEV; - } - msleep(10); - /* Read the manufacturer ID: ov = 0x7FA2 */ - if (stk_sensor_inb(dev, REG_MIDH, &idh) - || stk_sensor_inb(dev, REG_MIDL, &idl)) { - pr_err("Strange error reading sensor ID\n"); - return -ENODEV; - } - if (idh != 0x7f || idl != 0xa2) { - pr_err("Huh? you don't have a sensor from ovt\n"); - return -ENODEV; - } - if (stk_sensor_inb(dev, REG_PID, &idh) - || stk_sensor_inb(dev, REG_VER, &idl)) { - pr_err("Could not read sensor model\n"); - return -ENODEV; - } - stk_sensor_write_regvals(dev, ov_initvals); - msleep(10); - pr_info("OmniVision sensor detected, id %02X%02X at address %x\n", - idh, idl, SENSOR_ADDRESS); - return 0; -} - -/* V4L2_PIX_FMT_UYVY */ -static struct regval ov_fmt_uyvy[] = { - {REG_TSLB, TSLB_YLAST|0x08 }, - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ - {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; -/* V4L2_PIX_FMT_YUYV */ -static struct regval ov_fmt_yuyv[] = { - {REG_TSLB, 0 }, - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ - {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; - -/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */ -static struct regval ov_fmt_rgbr[] = { - { REG_RGB444, 0 }, /* No RGB444 please */ - {REG_TSLB, 0x00}, - { REG_COM1, 0x0 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA }, - { REG_COM15, COM15_RGB565|COM15_R00FF }, - { 0xff, 0xff }, -}; - -/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */ -static struct regval ov_fmt_rgbp[] = { - { REG_RGB444, 0 }, /* No RGB444 please */ - {REG_TSLB, TSLB_BYTEORD }, - { REG_COM1, 0x0 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA }, - { REG_COM15, COM15_RGB565|COM15_R00FF }, - { 0xff, 0xff }, -}; - -/* V4L2_PIX_FMT_SRGGB8 */ -static struct regval ov_fmt_bayer[] = { - /* This changes color order */ - {REG_TSLB, 0x40}, /* BGGR */ - /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */ - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; -/* - * Store a set of start/stop values into the camera. - */ -static int stk_sensor_set_hw(struct stk_camera *dev, - int hstart, int hstop, int vstart, int vstop) -{ - int ret; - unsigned char v; -/* - * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of - * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is - * a mystery "edge offset" value in the top two bits of href. - */ - ret = stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff); - ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff); - ret += stk_sensor_inb(dev, REG_HREF, &v); - v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); - msleep(10); - ret += stk_sensor_outb(dev, REG_HREF, v); -/* - * Vertical: similar arrangement (note: this is different from ov7670.c) - */ - ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff); - ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff); - ret += stk_sensor_inb(dev, REG_VREF, &v); - v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7); - msleep(10); - ret += stk_sensor_outb(dev, REG_VREF, v); - return ret; -} - - -int stk_sensor_configure(struct stk_camera *dev) -{ - int com7; - /* - * We setup the sensor to output dummy lines in low-res modes, - * so we don't get absurdly hight framerates. - */ - unsigned dummylines; - int flip; - struct regval *rv; - - switch (dev->vsettings.mode) { - case MODE_QCIF: com7 = COM7_FMT_QCIF; - dummylines = 604; - break; - case MODE_QVGA: com7 = COM7_FMT_QVGA; - dummylines = 267; - break; - case MODE_CIF: com7 = COM7_FMT_CIF; - dummylines = 412; - break; - case MODE_VGA: com7 = COM7_FMT_VGA; - dummylines = 11; - break; - case MODE_SXGA: com7 = COM7_FMT_SXGA; - dummylines = 0; - break; - default: - pr_err("Unsupported mode %d\n", dev->vsettings.mode); - return -EFAULT; - } - switch (dev->vsettings.palette) { - case V4L2_PIX_FMT_UYVY: - com7 |= COM7_YUV; - rv = ov_fmt_uyvy; - break; - case V4L2_PIX_FMT_YUYV: - com7 |= COM7_YUV; - rv = ov_fmt_yuyv; - break; - case V4L2_PIX_FMT_RGB565: - com7 |= COM7_RGB; - rv = ov_fmt_rgbp; - break; - case V4L2_PIX_FMT_RGB565X: - com7 |= COM7_RGB; - rv = ov_fmt_rgbr; - break; - case V4L2_PIX_FMT_SBGGR8: - com7 |= COM7_PBAYER; - rv = ov_fmt_bayer; - break; - default: - pr_err("Unsupported colorspace\n"); - return -EFAULT; - } - /*FIXME sometimes the sensor go to a bad state - stk_sensor_write_regvals(dev, ov_initvals); */ - stk_sensor_outb(dev, REG_COM7, com7); - msleep(50); - stk_sensor_write_regvals(dev, rv); - flip = (dev->vsettings.vflip?MVFP_FLIP:0) - | (dev->vsettings.hflip?MVFP_MIRROR:0); - stk_sensor_outb(dev, REG_MVFP, flip); - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8 - && !dev->vsettings.vflip) - stk_sensor_outb(dev, REG_TSLB, 0x08); - stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8); - stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff); - msleep(50); - switch (dev->vsettings.mode) { - case MODE_VGA: - if (stk_sensor_set_hw(dev, 302, 1582, 6, 486)) - pr_err("stk_sensor_set_hw failed (VGA)\n"); - break; - case MODE_SXGA: - case MODE_CIF: - case MODE_QVGA: - case MODE_QCIF: - /*FIXME These settings seem ignored by the sensor - if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034)) - pr_err("stk_sensor_set_hw failed (SXGA)\n"); - */ - break; - } - msleep(10); - return 0; -} - -int stk_sensor_set_brightness(struct stk_camera *dev, int br) -{ - if (br < 0 || br > 0xff) - return -EINVAL; - stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6)); - stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6)); - return 0; -} - diff --git a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c deleted file mode 100644 index a1b7ad350a90..000000000000 --- a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c +++ /dev/null @@ -1,1434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * stk-webcam.c : Driver for Syntek 1125 USB webcam controller - * - * Copyright (C) 2006 Nicolas VIVIEN - * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com> - * - * Some parts are inspired from cafe_ccic.c - * Copyright 2006-2007 Jonathan Corbet - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/slab.h> - -#include <linux/dmi.h> -#include <linux/usb.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-event.h> - -#include "stk-webcam.h" - - -static int hflip = -1; -module_param(hflip, int, 0444); -MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 0"); - -static int vflip = -1; -module_param(vflip, int, 0444); -MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 0"); - -static int debug; -module_param(debug, int, 0444); -MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0"); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN"); -MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); - -/* Some cameras have audio interfaces, we aren't interested in those */ -static const struct usb_device_id stkwebcam_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) }, - { } -}; -MODULE_DEVICE_TABLE(usb, stkwebcam_table); - -/* - * The stk webcam laptop module is mounted upside down in some laptops :( - * - * Some background information (thanks to Hans de Goede for providing this): - * - * 1) Once upon a time the stkwebcam driver was written - * - * 2) The webcam in question was used mostly in Asus laptop models, including - * the laptop of the original author of the driver, and in these models, in - * typical Asus fashion (see the long long list for uvc cams inside v4l-utils), - * they mounted the webcam-module the wrong way up. So the hflip and vflip - * module options were given a default value of 1 (the correct value for - * upside down mounted models) - * - * 3) Years later I got a bug report from a user with a laptop with stkwebcam, - * where the module was actually mounted the right way up, and thus showed - * upside down under Linux. So now I was facing the choice of 2 options: - * - * a) Add a not-upside-down list to stkwebcam, which overrules the default. - * - * b) Do it like all the other drivers do, and make the default right for - * cams mounted the proper way and add an upside-down model list, with - * models where we need to flip-by-default. - * - * Despite knowing that going b) would cause a period of pain where we were - * building the table I opted to go for option b), since a) is just too ugly, - * and worse different from how every other driver does it leading to - * confusion in the long run. This change was made in kernel 3.6. - * - * So for any user report about upside-down images since kernel 3.6 ask them - * to provide the output of 'sudo dmidecode' so the laptop can be added in - * the table below. - */ -static const struct dmi_system_id stk_upside_down_dmi_table[] = { - { - .ident = "ASUS G1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "G1") - } - }, { - .ident = "ASUS F3JC", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "F3JC") - } - }, - { - .ident = "T12Rg-H", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HCL Infosystems Limited"), - DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H") - } - }, - { - .ident = "ASUS A6VM", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") - } - }, - { - .ident = "ASUS A6JC", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") - } - }, - {} -}; - - -/* - * Basic stuff - */ -int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) -{ - struct usb_device *udev = dev->udev; - int ret; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x01, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - NULL, - 0, - 500); - if (ret < 0) - return ret; - else - return 0; -} - -int stk_camera_read_reg(struct stk_camera *dev, u16 index, u8 *value) -{ - struct usb_device *udev = dev->udev; - int ret; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, - index, - &dev->read_reg_scratch, - sizeof(u8), - 500); - if (ret >= 0) - *value = dev->read_reg_scratch; - - if (ret < 0) - return ret; - else - return 0; -} - -static int stk_start_stream(struct stk_camera *dev) -{ - u8 value; - int i, ret; - u8 value_116, value_117; - - - if (!is_present(dev)) - return -ENODEV; - if (!is_memallocd(dev) || !is_initialised(dev)) { - pr_err("FIXME: Buffers are not allocated\n"); - return -EFAULT; - } - ret = usb_set_interface(dev->udev, 0, 5); - - if (ret < 0) - pr_err("usb_set_interface failed !\n"); - if (stk_sensor_wakeup(dev)) - pr_err("error awaking the sensor\n"); - - stk_camera_read_reg(dev, 0x0116, &value_116); - stk_camera_read_reg(dev, 0x0117, &value_117); - - stk_camera_write_reg(dev, 0x0116, 0x0000); - stk_camera_write_reg(dev, 0x0117, 0x0000); - - stk_camera_read_reg(dev, 0x0100, &value); - stk_camera_write_reg(dev, 0x0100, value | 0x80); - - stk_camera_write_reg(dev, 0x0116, value_116); - stk_camera_write_reg(dev, 0x0117, value_117); - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].urb) { - ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL); - atomic_inc(&dev->urbs_used); - if (ret) - return ret; - } - } - set_streaming(dev); - return 0; -} - -static int stk_stop_stream(struct stk_camera *dev) -{ - u8 value; - int i; - if (is_present(dev)) { - stk_camera_read_reg(dev, 0x0100, &value); - stk_camera_write_reg(dev, 0x0100, value & ~0x80); - if (dev->isobufs != NULL) { - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].urb) - usb_kill_urb(dev->isobufs[i].urb); - } - } - unset_streaming(dev); - - if (usb_set_interface(dev->udev, 0, 0)) - pr_err("usb_set_interface failed !\n"); - if (stk_sensor_sleep(dev)) - pr_err("error suspending the sensor\n"); - } - return 0; -} - -/* - * This seems to be the shortest init sequence we - * must do in order to find the sensor - * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor - * is also reset. Maybe powers down it? - * Rest of values don't make a difference - */ - -static struct regval stk1125_initvals[] = { - /*TODO: What means this sequence? */ - {0x0000, 0x24}, - {0x0100, 0x21}, - {0x0002, 0x68}, - {0x0003, 0x80}, - {0x0005, 0x00}, - {0x0007, 0x03}, - {0x000d, 0x00}, - {0x000f, 0x02}, - {0x0300, 0x12}, - {0x0350, 0x41}, - {0x0351, 0x00}, - {0x0352, 0x00}, - {0x0353, 0x00}, - {0x0018, 0x10}, - {0x0019, 0x00}, - {0x001b, 0x0e}, - {0x001c, 0x46}, - {0x0300, 0x80}, - {0x001a, 0x04}, - {0x0110, 0x00}, - {0x0111, 0x00}, - {0x0112, 0x00}, - {0x0113, 0x00}, - - {0xffff, 0xff}, -}; - - -static int stk_initialise(struct stk_camera *dev) -{ - struct regval *rv; - int ret; - if (!is_present(dev)) - return -ENODEV; - if (is_initialised(dev)) - return 0; - rv = stk1125_initvals; - while (rv->reg != 0xffff) { - ret = stk_camera_write_reg(dev, rv->reg, rv->val); - if (ret) - return ret; - rv++; - } - if (stk_sensor_init(dev) == 0) { - set_initialised(dev); - return 0; - } else - return -1; -} - -/* *********************************************** */ -/* - * This function is called as an URB transfert is complete (Isochronous pipe). - * So, the traitement is done in interrupt time, so it has be fast, not crash, - * and not stall. Neat. - */ -static void stk_isoc_handler(struct urb *urb) -{ - int i; - int ret; - int framelen; - unsigned long flags; - - unsigned char *fill = NULL; - unsigned char *iso_buf = NULL; - - struct stk_camera *dev; - struct stk_sio_buffer *fb; - - dev = (struct stk_camera *) urb->context; - - if (dev == NULL) { - pr_err("isoc_handler called with NULL device !\n"); - return; - } - - if (urb->status == -ENOENT || urb->status == -ECONNRESET - || urb->status == -ESHUTDOWN) { - atomic_dec(&dev->urbs_used); - return; - } - - spin_lock_irqsave(&dev->spinlock, flags); - - if (urb->status != -EINPROGRESS && urb->status != 0) { - pr_err("isoc_handler: urb->status == %d\n", urb->status); - goto resubmit; - } - - if (list_empty(&dev->sio_avail)) { - /*FIXME Stop streaming after a while */ - pr_err_ratelimited("isoc_handler without available buffer!\n"); - goto resubmit; - } - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fill = fb->buffer + fb->v4lbuf.bytesused; - - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status != 0) { - if (urb->iso_frame_desc[i].status != -EXDEV) - pr_err("Frame %d has error %d\n", - i, urb->iso_frame_desc[i].status); - continue; - } - framelen = urb->iso_frame_desc[i].actual_length; - iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - if (framelen <= 4) - continue; /* no data */ - - /* - * we found something informational from there - * the isoc frames have to type of headers - * type1: 00 xx 00 00 or 20 xx 00 00 - * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00 - * xx is a sequencer which has never been seen over 0x3f - * imho data written down looks like bayer, i see similarities - * after every 640 bytes - */ - if (*iso_buf & 0x80) { - framelen -= 8; - iso_buf += 8; - /* This marks a new frame */ - if (fb->v4lbuf.bytesused != 0 - && fb->v4lbuf.bytesused != dev->frame_size) { - pr_err_ratelimited("frame %d, bytesused=%d, skipping\n", - i, fb->v4lbuf.bytesused); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } else if (fb->v4lbuf.bytesused == dev->frame_size) { - if (list_is_singular(&dev->sio_avail)) { - /* Always reuse the last buffer */ - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } else { - list_move_tail(dev->sio_avail.next, - &dev->sio_full); - wake_up(&dev->wait_frame); - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } - } - } else { - framelen -= 4; - iso_buf += 4; - } - - /* Our buffer is full !!! */ - if (framelen + fb->v4lbuf.bytesused > dev->frame_size) { - pr_err_ratelimited("Frame buffer overflow, lost sync\n"); - /*FIXME Do something here? */ - continue; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - memcpy(fill, iso_buf, framelen); - spin_lock_irqsave(&dev->spinlock, flags); - fill += framelen; - - /* New size of our buffer */ - fb->v4lbuf.bytesused += framelen; - } - -resubmit: - spin_unlock_irqrestore(&dev->spinlock, flags); - urb->dev = dev->udev; - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret != 0) { - pr_err("Error (%d) re-submitting urb in stk_isoc_handler\n", - ret); - } -} - -/* -------------------------------------------- */ - -static int stk_prepare_iso(struct stk_camera *dev) -{ - void *kbuf; - int i, j; - struct urb *urb; - struct usb_device *udev; - - if (dev == NULL) - return -ENXIO; - udev = dev->udev; - - if (dev->isobufs) - pr_err("isobufs already allocated. Bad\n"); - else - dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs), - GFP_KERNEL); - if (dev->isobufs == NULL) { - pr_err("Unable to allocate iso buffers\n"); - return -ENOMEM; - } - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].data == NULL) { - kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); - if (kbuf == NULL) { - pr_err("Failed to allocate iso buffer %d\n", i); - goto isobufs_out; - } - dev->isobufs[i].data = kbuf; - } else - pr_err("isobuf data already allocated\n"); - if (dev->isobufs[i].urb == NULL) { - urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); - if (urb == NULL) - goto isobufs_out; - dev->isobufs[i].urb = urb; - } else { - pr_err("Killing URB\n"); - usb_kill_urb(dev->isobufs[i].urb); - urb = dev->isobufs[i].urb; - } - urb->interval = 1; - urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->isobufs[i].data; - urb->transfer_buffer_length = ISO_BUFFER_SIZE; - urb->complete = stk_isoc_handler; - urb->context = dev; - urb->start_frame = 0; - urb->number_of_packets = ISO_FRAMES_PER_DESC; - - for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; - urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; - } - } - set_memallocd(dev); - return 0; - -isobufs_out: - for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++) - kfree(dev->isobufs[i].data); - for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++) - usb_free_urb(dev->isobufs[i].urb); - kfree(dev->isobufs); - dev->isobufs = NULL; - return -ENOMEM; -} - -static void stk_clean_iso(struct stk_camera *dev) -{ - int i; - - if (dev == NULL || dev->isobufs == NULL) - return; - - for (i = 0; i < MAX_ISO_BUFS; i++) { - struct urb *urb; - - urb = dev->isobufs[i].urb; - if (urb) { - if (atomic_read(&dev->urbs_used) && is_present(dev)) - usb_kill_urb(urb); - usb_free_urb(urb); - } - kfree(dev->isobufs[i].data); - } - kfree(dev->isobufs); - dev->isobufs = NULL; - unset_memallocd(dev); -} - -static int stk_setup_siobuf(struct stk_camera *dev, int index) -{ - struct stk_sio_buffer *buf = dev->sio_bufs + index; - INIT_LIST_HEAD(&buf->list); - buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size); - buf->buffer = vmalloc_user(buf->v4lbuf.length); - if (buf->buffer == NULL) - return -ENOMEM; - buf->mapcount = 0; - buf->dev = dev; - buf->v4lbuf.index = index; - buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->v4lbuf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - buf->v4lbuf.field = V4L2_FIELD_NONE; - buf->v4lbuf.memory = V4L2_MEMORY_MMAP; - buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; - return 0; -} - -static int stk_free_sio_buffers(struct stk_camera *dev) -{ - int i; - int nbufs; - unsigned long flags; - if (dev->n_sbufs == 0 || dev->sio_bufs == NULL) - return 0; - /* - * If any buffers are mapped, we cannot free them at all. - */ - for (i = 0; i < dev->n_sbufs; i++) { - if (dev->sio_bufs[i].mapcount > 0) - return -EBUSY; - } - /* - * OK, let's do it. - */ - spin_lock_irqsave(&dev->spinlock, flags); - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - nbufs = dev->n_sbufs; - dev->n_sbufs = 0; - spin_unlock_irqrestore(&dev->spinlock, flags); - for (i = 0; i < nbufs; i++) - vfree(dev->sio_bufs[i].buffer); - kfree(dev->sio_bufs); - dev->sio_bufs = NULL; - return 0; -} - -static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs) -{ - int i; - if (dev->sio_bufs != NULL) - pr_err("sio_bufs already allocated\n"); - else { - dev->sio_bufs = kcalloc(n_sbufs, - sizeof(struct stk_sio_buffer), - GFP_KERNEL); - if (dev->sio_bufs == NULL) - return -ENOMEM; - for (i = 0; i < n_sbufs; i++) { - if (stk_setup_siobuf(dev, i)) - return (dev->n_sbufs > 1 ? 0 : -ENOMEM); - dev->n_sbufs = i+1; - } - } - return 0; -} - -static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs) -{ - int err; - err = stk_prepare_iso(dev); - if (err) { - stk_clean_iso(dev); - return err; - } - err = stk_prepare_sio_buffers(dev, n_sbufs); - if (err) { - stk_free_sio_buffers(dev); - return err; - } - return 0; -} - -static void stk_free_buffers(struct stk_camera *dev) -{ - stk_clean_iso(dev); - stk_free_sio_buffers(dev); -} -/* -------------------------------------------- */ - -/* v4l file operations */ - -static int v4l_stk_open(struct file *fp) -{ - struct stk_camera *dev = video_drvdata(fp); - int err; - - if (dev == NULL || !is_present(dev)) - return -ENXIO; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - if (!dev->first_init) - stk_camera_write_reg(dev, 0x0, 0x24); - else - dev->first_init = 0; - - err = v4l2_fh_open(fp); - if (!err) - usb_autopm_get_interface(dev->interface); - mutex_unlock(&dev->lock); - return err; -} - -static int v4l_stk_release(struct file *fp) -{ - struct stk_camera *dev = video_drvdata(fp); - - mutex_lock(&dev->lock); - if (dev->owner == fp) { - stk_stop_stream(dev); - stk_free_buffers(dev); - stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */ - unset_initialised(dev); - dev->owner = NULL; - } - - usb_autopm_put_interface(dev->interface); - mutex_unlock(&dev->lock); - return v4l2_fh_release(fp); -} - -static ssize_t stk_read(struct file *fp, char __user *buf, - size_t count, loff_t *f_pos) -{ - int i; - int ret; - unsigned long flags; - struct stk_sio_buffer *sbuf; - struct stk_camera *dev = video_drvdata(fp); - - if (!is_present(dev)) - return -EIO; - if (dev->owner && (!dev->reading || dev->owner != fp)) - return -EBUSY; - dev->owner = fp; - if (!is_streaming(dev)) { - if (stk_initialise(dev) - || stk_allocate_buffers(dev, 3) - || stk_start_stream(dev)) - return -ENOMEM; - dev->reading = 1; - spin_lock_irqsave(&dev->spinlock, flags); - for (i = 0; i < dev->n_sbufs; i++) { - list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail); - dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - } - if (*f_pos == 0) { - if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) - return -EWOULDBLOCK; - ret = wait_event_interruptible(dev->wait_frame, - !list_empty(&dev->sio_full) || !is_present(dev)); - if (ret) - return ret; - if (!is_present(dev)) - return -EIO; - } - if (count + *f_pos > dev->frame_size) - count = dev->frame_size - *f_pos; - spin_lock_irqsave(&dev->spinlock, flags); - if (list_empty(&dev->sio_full)) { - spin_unlock_irqrestore(&dev->spinlock, flags); - pr_err("BUG: No siobufs ready\n"); - return 0; - } - sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); - spin_unlock_irqrestore(&dev->spinlock, flags); - - if (copy_to_user(buf, sbuf->buffer + *f_pos, count)) - return -EFAULT; - - *f_pos += count; - - if (*f_pos >= dev->frame_size) { - *f_pos = 0; - spin_lock_irqsave(&dev->spinlock, flags); - list_move_tail(&sbuf->list, &dev->sio_avail); - spin_unlock_irqrestore(&dev->spinlock, flags); - } - return count; -} - -static ssize_t v4l_stk_read(struct file *fp, char __user *buf, - size_t count, loff_t *f_pos) -{ - struct stk_camera *dev = video_drvdata(fp); - int ret; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - ret = stk_read(fp, buf, count, f_pos); - mutex_unlock(&dev->lock); - return ret; -} - -static __poll_t v4l_stk_poll(struct file *fp, poll_table *wait) -{ - struct stk_camera *dev = video_drvdata(fp); - __poll_t res = v4l2_ctrl_poll(fp, wait); - - poll_wait(fp, &dev->wait_frame, wait); - - if (!is_present(dev)) - return EPOLLERR; - - if (!list_empty(&dev->sio_full)) - return res | EPOLLIN | EPOLLRDNORM; - - return res; -} - - -static void stk_v4l_vm_open(struct vm_area_struct *vma) -{ - struct stk_sio_buffer *sbuf = vma->vm_private_data; - sbuf->mapcount++; -} -static void stk_v4l_vm_close(struct vm_area_struct *vma) -{ - struct stk_sio_buffer *sbuf = vma->vm_private_data; - sbuf->mapcount--; - if (sbuf->mapcount == 0) - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; -} -static const struct vm_operations_struct stk_v4l_vm_ops = { - .open = stk_v4l_vm_open, - .close = stk_v4l_vm_close -}; - -static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) -{ - unsigned int i; - int ret; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct stk_camera *dev = video_drvdata(fp); - struct stk_sio_buffer *sbuf = NULL; - - if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) - return -EINVAL; - - for (i = 0; i < dev->n_sbufs; i++) { - if (dev->sio_bufs[i].v4lbuf.m.offset == offset) { - sbuf = dev->sio_bufs + i; - break; - } - } - if (sbuf == NULL) - return -EINVAL; - ret = remap_vmalloc_range(vma, sbuf->buffer, 0); - if (ret) - return ret; - vm_flags_set(vma, VM_DONTEXPAND); - vma->vm_private_data = sbuf; - vma->vm_ops = &stk_v4l_vm_ops; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; - stk_v4l_vm_open(vma); - return 0; -} - -/* v4l ioctl handlers */ - -static int stk_vidioc_querycap(struct file *filp, - void *priv, struct v4l2_capability *cap) -{ - struct stk_camera *dev = video_drvdata(filp); - - strscpy(cap->driver, "stk", sizeof(cap->driver)); - strscpy(cap->card, "stk", sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - return 0; -} - -static int stk_vidioc_enum_input(struct file *filp, - void *priv, struct v4l2_input *input) -{ - if (input->index != 0) - return -EINVAL; - - strscpy(input->name, "Syntek USB Camera", sizeof(input->name)); - input->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - - -static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int stk_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct stk_camera *dev = - container_of(ctrl->handler, struct stk_camera, hdl); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - return stk_sensor_set_brightness(dev, ctrl->val); - case V4L2_CID_HFLIP: - if (dmi_check_system(stk_upside_down_dmi_table)) - dev->vsettings.hflip = !ctrl->val; - else - dev->vsettings.hflip = ctrl->val; - return 0; - case V4L2_CID_VFLIP: - if (dmi_check_system(stk_upside_down_dmi_table)) - dev->vsettings.vflip = !ctrl->val; - else - dev->vsettings.vflip = ctrl->val; - return 0; - default: - return -EINVAL; - } - return 0; -} - - -static int stk_vidioc_enum_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_fmtdesc *fmtd) -{ - switch (fmtd->index) { - case 0: - fmtd->pixelformat = V4L2_PIX_FMT_RGB565; - break; - case 1: - fmtd->pixelformat = V4L2_PIX_FMT_RGB565X; - break; - case 2: - fmtd->pixelformat = V4L2_PIX_FMT_UYVY; - break; - case 3: - fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; - break; - case 4: - fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - break; - default: - return -EINVAL; - } - return 0; -} - -static struct stk_size { - unsigned w; - unsigned h; - enum stk_mode m; -} stk_sizes[] = { - { .w = 1280, .h = 1024, .m = MODE_SXGA, }, - { .w = 640, .h = 480, .m = MODE_VGA, }, - { .w = 352, .h = 288, .m = MODE_CIF, }, - { .w = 320, .h = 240, .m = MODE_QVGA, }, - { .w = 176, .h = 144, .m = MODE_QCIF, }, -}; - -static int stk_vidioc_g_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format *pix_format = &f->fmt.pix; - struct stk_camera *dev = video_drvdata(filp); - int i; - - for (i = 0; i < ARRAY_SIZE(stk_sizes) && - stk_sizes[i].m != dev->vsettings.mode; i++) - ; - if (i == ARRAY_SIZE(stk_sizes)) { - pr_err("ERROR: mode invalid\n"); - return -EINVAL; - } - pix_format->width = stk_sizes[i].w; - pix_format->height = stk_sizes[i].h; - pix_format->field = V4L2_FIELD_NONE; - pix_format->colorspace = V4L2_COLORSPACE_SRGB; - pix_format->pixelformat = dev->vsettings.palette; - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) - pix_format->bytesperline = pix_format->width; - else - pix_format->bytesperline = 2 * pix_format->width; - pix_format->sizeimage = pix_format->bytesperline - * pix_format->height; - return 0; -} - -static int stk_try_fmt_vid_cap(struct file *filp, - struct v4l2_format *fmtd, int *idx) -{ - int i; - switch (fmtd->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_SBGGR8: - break; - default: - return -EINVAL; - } - for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) { - if (fmtd->fmt.pix.width > stk_sizes[i].w) - break; - } - if (i == ARRAY_SIZE(stk_sizes) - || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w) - < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) { - fmtd->fmt.pix.height = stk_sizes[i-1].h; - fmtd->fmt.pix.width = stk_sizes[i-1].w; - if (idx) - *idx = i - 1; - } else { - fmtd->fmt.pix.height = stk_sizes[i].h; - fmtd->fmt.pix.width = stk_sizes[i].w; - if (idx) - *idx = i; - } - - fmtd->fmt.pix.field = V4L2_FIELD_NONE; - fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) - fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width; - else - fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; - fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline - * fmtd->fmt.pix.height; - return 0; -} - -static int stk_vidioc_try_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_format *fmtd) -{ - return stk_try_fmt_vid_cap(filp, fmtd, NULL); -} - -static int stk_setup_format(struct stk_camera *dev) -{ - int i = 0; - int depth; - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) - depth = 1; - else - depth = 2; - while (i < ARRAY_SIZE(stk_sizes) && - stk_sizes[i].m != dev->vsettings.mode) - i++; - if (i == ARRAY_SIZE(stk_sizes)) { - pr_err("Something is broken in %s\n", __func__); - return -EFAULT; - } - /* This registers controls some timings, not sure of what. */ - stk_camera_write_reg(dev, 0x001b, 0x0e); - if (dev->vsettings.mode == MODE_SXGA) - stk_camera_write_reg(dev, 0x001c, 0x0e); - else - stk_camera_write_reg(dev, 0x001c, 0x46); - /* - * Registers 0x0115 0x0114 are the size of each line (bytes), - * regs 0x0117 0x0116 are the height of the image. - */ - stk_camera_write_reg(dev, 0x0115, - ((stk_sizes[i].w * depth) >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0114, - (stk_sizes[i].w * depth) & 0xff); - stk_camera_write_reg(dev, 0x0117, - (stk_sizes[i].h >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0116, - stk_sizes[i].h & 0xff); - return stk_sensor_configure(dev); -} - -static int stk_vidioc_s_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_format *fmtd) -{ - int ret; - int idx; - struct stk_camera *dev = video_drvdata(filp); - - if (dev == NULL) - return -ENODEV; - if (!is_present(dev)) - return -ENODEV; - if (is_streaming(dev)) - return -EBUSY; - if (dev->owner) - return -EBUSY; - ret = stk_try_fmt_vid_cap(filp, fmtd, &idx); - if (ret) - return ret; - - dev->vsettings.palette = fmtd->fmt.pix.pixelformat; - stk_free_buffers(dev); - dev->frame_size = fmtd->fmt.pix.sizeimage; - dev->vsettings.mode = stk_sizes[idx].m; - - stk_initialise(dev); - return stk_setup_format(dev); -} - -static int stk_vidioc_reqbufs(struct file *filp, - void *priv, struct v4l2_requestbuffers *rb) -{ - struct stk_camera *dev = video_drvdata(filp); - - if (dev == NULL) - return -ENODEV; - if (rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - if (is_streaming(dev) - || (dev->owner && dev->owner != filp)) - return -EBUSY; - stk_free_buffers(dev); - if (rb->count == 0) { - stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */ - unset_initialised(dev); - dev->owner = NULL; - return 0; - } - dev->owner = filp; - - /*FIXME If they ask for zero, we must stop streaming and free */ - if (rb->count < 3) - rb->count = 3; - /* Arbitrary limit */ - else if (rb->count > 5) - rb->count = 5; - - stk_allocate_buffers(dev, rb->count); - rb->count = dev->n_sbufs; - return 0; -} - -static int stk_vidioc_querybuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = video_drvdata(filp); - struct stk_sio_buffer *sbuf; - - if (buf->index >= dev->n_sbufs) - return -EINVAL; - sbuf = dev->sio_bufs + buf->index; - *buf = sbuf->v4lbuf; - return 0; -} - -static int stk_vidioc_qbuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = video_drvdata(filp); - struct stk_sio_buffer *sbuf; - unsigned long flags; - - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (buf->index >= dev->n_sbufs) - return -EINVAL; - sbuf = dev->sio_bufs + buf->index; - if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) - return 0; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; - spin_lock_irqsave(&dev->spinlock, flags); - list_add_tail(&sbuf->list, &dev->sio_avail); - *buf = sbuf->v4lbuf; - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; -} - -static int stk_vidioc_dqbuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = video_drvdata(filp); - struct stk_sio_buffer *sbuf; - unsigned long flags; - int ret; - - if (!is_streaming(dev)) - return -EINVAL; - - if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) - return -EWOULDBLOCK; - ret = wait_event_interruptible(dev->wait_frame, - !list_empty(&dev->sio_full) || !is_present(dev)); - if (ret) - return ret; - if (!is_present(dev)) - return -EIO; - - spin_lock_irqsave(&dev->spinlock, flags); - sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); - list_del_init(&sbuf->list); - spin_unlock_irqrestore(&dev->spinlock, flags); - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; - sbuf->v4lbuf.sequence = ++dev->sequence; - v4l2_buffer_set_timestamp(&sbuf->v4lbuf, ktime_get_ns()); - - *buf = sbuf->v4lbuf; - return 0; -} - -static int stk_vidioc_streamon(struct file *filp, - void *priv, enum v4l2_buf_type type) -{ - struct stk_camera *dev = video_drvdata(filp); - if (is_streaming(dev)) - return 0; - if (dev->sio_bufs == NULL) - return -EINVAL; - dev->sequence = 0; - return stk_start_stream(dev); -} - -static int stk_vidioc_streamoff(struct file *filp, - void *priv, enum v4l2_buf_type type) -{ - struct stk_camera *dev = video_drvdata(filp); - unsigned long flags; - int i; - stk_stop_stream(dev); - spin_lock_irqsave(&dev->spinlock, flags); - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - for (i = 0; i < dev->n_sbufs; i++) { - INIT_LIST_HEAD(&dev->sio_bufs[i].list); - dev->sio_bufs[i].v4lbuf.flags = 0; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; -} - - -static int stk_vidioc_g_parm(struct file *filp, - void *priv, struct v4l2_streamparm *sp) -{ - /*FIXME This is not correct */ - sp->parm.capture.timeperframe.numerator = 1; - sp->parm.capture.timeperframe.denominator = 30; - sp->parm.capture.readbuffers = 2; - return 0; -} - -static int stk_vidioc_enum_framesizes(struct file *filp, - void *priv, struct v4l2_frmsizeenum *frms) -{ - if (frms->index >= ARRAY_SIZE(stk_sizes)) - return -EINVAL; - switch (frms->pixel_format) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_SBGGR8: - frms->type = V4L2_FRMSIZE_TYPE_DISCRETE; - frms->discrete.width = stk_sizes[frms->index].w; - frms->discrete.height = stk_sizes[frms->index].h; - return 0; - default: return -EINVAL; - } -} - -static const struct v4l2_ctrl_ops stk_ctrl_ops = { - .s_ctrl = stk_s_ctrl, -}; - -static const struct v4l2_file_operations v4l_stk_fops = { - .owner = THIS_MODULE, - .open = v4l_stk_open, - .release = v4l_stk_release, - .read = v4l_stk_read, - .poll = v4l_stk_poll, - .mmap = v4l_stk_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { - .vidioc_querycap = stk_vidioc_querycap, - .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap, - .vidioc_enum_input = stk_vidioc_enum_input, - .vidioc_s_input = stk_vidioc_s_input, - .vidioc_g_input = stk_vidioc_g_input, - .vidioc_reqbufs = stk_vidioc_reqbufs, - .vidioc_querybuf = stk_vidioc_querybuf, - .vidioc_qbuf = stk_vidioc_qbuf, - .vidioc_dqbuf = stk_vidioc_dqbuf, - .vidioc_streamon = stk_vidioc_streamon, - .vidioc_streamoff = stk_vidioc_streamoff, - .vidioc_g_parm = stk_vidioc_g_parm, - .vidioc_enum_framesizes = stk_vidioc_enum_framesizes, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static void stk_v4l_dev_release(struct video_device *vd) -{ - struct stk_camera *dev = vdev_to_camera(vd); - - if (dev->sio_bufs != NULL || dev->isobufs != NULL) - pr_err("We are leaking memory\n"); - usb_put_intf(dev->interface); - usb_put_dev(dev->udev); - - v4l2_ctrl_handler_free(&dev->hdl); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); -} - -static const struct video_device stk_v4l_data = { - .name = "stkwebcam", - .fops = &v4l_stk_fops, - .ioctl_ops = &v4l_stk_ioctl_ops, - .release = stk_v4l_dev_release, -}; - - -static int stk_register_video_device(struct stk_camera *dev) -{ - int err; - - dev->vdev = stk_v4l_data; - dev->vdev.lock = &dev->lock; - dev->vdev.v4l2_dev = &dev->v4l2_dev; - dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - video_set_drvdata(&dev->vdev, dev); - err = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1); - if (err) - pr_err("v4l registration failed\n"); - else - pr_info("Syntek USB2.0 Camera is now controlling device %s\n", - video_device_node_name(&dev->vdev)); - return err; -} - - -/* USB Stuff */ - -static int stk_camera_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct v4l2_ctrl_handler *hdl; - int err = 0; - int i; - - struct stk_camera *dev = NULL; - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - - dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL); - if (dev == NULL) { - pr_err("Out of memory !\n"); - return -ENOMEM; - } - err = v4l2_device_register(&interface->dev, &dev->v4l2_dev); - if (err < 0) { - dev_err(&udev->dev, "couldn't register v4l2_device\n"); - kfree(dev); - return err; - } - hdl = &dev->hdl; - v4l2_ctrl_handler_init(hdl, 3); - v4l2_ctrl_new_std(hdl, &stk_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 0xff, 0x1, 0x60); - v4l2_ctrl_new_std(hdl, &stk_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 1); - v4l2_ctrl_new_std(hdl, &stk_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 1); - if (hdl->error) { - err = hdl->error; - dev_err(&udev->dev, "couldn't register control\n"); - goto error; - } - dev->v4l2_dev.ctrl_handler = hdl; - - spin_lock_init(&dev->spinlock); - mutex_init(&dev->lock); - init_waitqueue_head(&dev->wait_frame); - dev->first_init = 1; /* webcam LED management */ - - dev->udev = usb_get_dev(udev); - dev->interface = interface; - usb_get_intf(interface); - - if (hflip != -1) - dev->vsettings.hflip = hflip; - else if (dmi_check_system(stk_upside_down_dmi_table)) - dev->vsettings.hflip = 1; - else - dev->vsettings.hflip = 0; - if (vflip != -1) - dev->vsettings.vflip = vflip; - else if (dmi_check_system(stk_upside_down_dmi_table)) - dev->vsettings.vflip = 1; - else - dev->vsettings.vflip = 0; - dev->n_sbufs = 0; - set_present(dev); - - /* Set up the endpoint information - * use only the first isoc-in endpoint - * for the current alternate setting */ - iface_desc = interface->cur_altsetting; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!dev->isoc_ep - && usb_endpoint_is_isoc_in(endpoint)) { - /* we found an isoc in endpoint */ - dev->isoc_ep = usb_endpoint_num(endpoint); - break; - } - } - if (!dev->isoc_ep) { - pr_err("Could not find isoc-in endpoint\n"); - err = -ENODEV; - goto error_put; - } - dev->vsettings.palette = V4L2_PIX_FMT_RGB565; - dev->vsettings.mode = MODE_VGA; - dev->frame_size = 640 * 480 * 2; - - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - - usb_set_intfdata(interface, dev); - - err = stk_register_video_device(dev); - if (err) - goto error_put; - - return 0; - -error_put: - usb_put_intf(interface); - usb_put_dev(dev->udev); -error: - v4l2_ctrl_handler_free(hdl); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - return err; -} - -static void stk_camera_disconnect(struct usb_interface *interface) -{ - struct stk_camera *dev = usb_get_intfdata(interface); - - usb_set_intfdata(interface, NULL); - unset_present(dev); - - wake_up_interruptible(&dev->wait_frame); - - pr_info("Syntek USB2.0 Camera release resources device %s\n", - video_device_node_name(&dev->vdev)); - - video_unregister_device(&dev->vdev); -} - -#ifdef CONFIG_PM -static int stk_camera_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct stk_camera *dev = usb_get_intfdata(intf); - if (is_streaming(dev)) { - stk_stop_stream(dev); - /* yes, this is ugly */ - set_streaming(dev); - } - return 0; -} - -static int stk_camera_resume(struct usb_interface *intf) -{ - struct stk_camera *dev = usb_get_intfdata(intf); - if (!is_initialised(dev)) - return 0; - unset_initialised(dev); - stk_initialise(dev); - stk_camera_write_reg(dev, 0x0, 0x49); - stk_setup_format(dev); - if (is_streaming(dev)) - stk_start_stream(dev); - return 0; -} -#endif - -static struct usb_driver stk_camera_driver = { - .name = "stkwebcam", - .probe = stk_camera_probe, - .disconnect = stk_camera_disconnect, - .id_table = stkwebcam_table, -#ifdef CONFIG_PM - .suspend = stk_camera_suspend, - .resume = stk_camera_resume, -#endif -}; - -module_usb_driver(stk_camera_driver); diff --git a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h deleted file mode 100644 index 136decffe9ce..000000000000 --- a/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * stk-webcam.h : Driver for Syntek 1125 USB webcam controller - * - * Copyright (C) 2006 Nicolas VIVIEN - * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com> - */ - -#ifndef STKWEBCAM_H -#define STKWEBCAM_H - -#include <linux/usb.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-common.h> - -#define DRIVER_VERSION "v0.0.1" -#define DRIVER_VERSION_NUM 0x000001 - -#define MAX_ISO_BUFS 3 -#define ISO_FRAMES_PER_DESC 16 -#define ISO_MAX_FRAME_SIZE 3 * 1024 -#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) - -struct stk_iso_buf { - void *data; - int length; - int read; - struct urb *urb; -}; - -/* Streaming IO buffers */ -struct stk_sio_buffer { - struct v4l2_buffer v4lbuf; - char *buffer; - int mapcount; - struct stk_camera *dev; - struct list_head list; -}; - -enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF}; - -struct stk_video { - enum stk_mode mode; - __u32 palette; - int hflip; - int vflip; -}; - -enum stk_status { - S_PRESENT = 1, - S_INITIALISED = 2, - S_MEMALLOCD = 4, - S_STREAMING = 8, -}; -#define is_present(dev) ((dev)->status & S_PRESENT) -#define is_initialised(dev) ((dev)->status & S_INITIALISED) -#define is_streaming(dev) ((dev)->status & S_STREAMING) -#define is_memallocd(dev) ((dev)->status & S_MEMALLOCD) -#define set_present(dev) ((dev)->status = S_PRESENT) -#define unset_present(dev) ((dev)->status &= \ - ~(S_PRESENT|S_INITIALISED|S_STREAMING)) -#define set_initialised(dev) ((dev)->status |= S_INITIALISED) -#define unset_initialised(dev) ((dev)->status &= ~S_INITIALISED) -#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD) -#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD) -#define set_streaming(dev) ((dev)->status |= S_STREAMING) -#define unset_streaming(dev) ((dev)->status &= ~S_STREAMING) - -struct regval { - unsigned reg; - unsigned val; -}; - -struct stk_camera { - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler hdl; - struct video_device vdev; - struct usb_device *udev; - struct usb_interface *interface; - int webcam_model; - struct file *owner; - struct mutex lock; - int first_init; - - u8 isoc_ep; - - /* Not sure if this is right */ - atomic_t urbs_used; - - struct stk_video vsettings; - - enum stk_status status; - - spinlock_t spinlock; - wait_queue_head_t wait_frame; - - struct stk_iso_buf *isobufs; - - int frame_size; - /* Streaming buffers */ - int reading; - unsigned int n_sbufs; - struct stk_sio_buffer *sio_bufs; - struct list_head sio_avail; - struct list_head sio_full; - unsigned sequence; - - u8 read_reg_scratch; -}; - -#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) - -int stk_camera_write_reg(struct stk_camera *, u16, u8); -int stk_camera_read_reg(struct stk_camera *, u16, u8 *); - -int stk_sensor_init(struct stk_camera *); -int stk_sensor_configure(struct stk_camera *); -int stk_sensor_sleep(struct stk_camera *dev); -int stk_sensor_wakeup(struct stk_camera *dev); -int stk_sensor_set_brightness(struct stk_camera *dev, int br); - -#endif diff --git a/drivers/staging/media/deprecated/tm6000/Kconfig b/drivers/staging/media/deprecated/tm6000/Kconfig deleted file mode 100644 index 73d72e49eb28..000000000000 --- a/drivers/staging/media/deprecated/tm6000/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_TM6000 - tristate "TV Master TM5600/6000/6010 driver (DEPRECATED)" - depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB - select VIDEO_TUNER - select MEDIA_TUNER_XC2028 - select MEDIA_TUNER_XC5000 - select VIDEOBUF_VMALLOC - help - Support for TM5600/TM6000/TM6010 USB Device - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the usb bus, so you need - an external software decoder to watch TV on your computer. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - Say Y if you own such a device and want to use it. - -config VIDEO_TM6000_ALSA - tristate "TV Master TM5600/6000/6010 audio support" - depends on VIDEO_TM6000 && SND - select SND_PCM - help - This is a video4linux driver for direct (DMA) audio for - TM5600/TM6000/TM6010 USB Devices. - - To compile this driver as a module, choose M here: the - module will be called tm6000-alsa. - -config VIDEO_TM6000_DVB - tristate "DVB Support for tm6000 based TV cards" - depends on VIDEO_TM6000 && DVB_CORE && USB - select DVB_ZL10353 - help - This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/drivers/staging/media/deprecated/tm6000/Makefile b/drivers/staging/media/deprecated/tm6000/Makefile deleted file mode 100644 index 75247a02a485..000000000000 --- a/drivers/staging/media/deprecated/tm6000/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -tm6000-y := tm6000-cards.o \ - tm6000-core.o \ - tm6000-i2c.o \ - tm6000-video.o \ - tm6000-stds.o \ - tm6000-input.o - -obj-$(CONFIG_VIDEO_TM6000) += tm6000.o -obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o -obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o - -ccflags-y += -I $(srctree)/drivers/media/tuners -ccflags-y += -I $(srctree)/drivers/media/dvb-frontends diff --git a/drivers/staging/media/deprecated/tm6000/TODO b/drivers/staging/media/deprecated/tm6000/TODO deleted file mode 100644 index ecb30a429689..000000000000 --- a/drivers/staging/media/deprecated/tm6000/TODO +++ /dev/null @@ -1,7 +0,0 @@ -This is one of the few drivers still not using the vb2 -framework, so this driver is now deprecated with the intent of -removing it altogether by the beginning of 2023. - -In order to keep this driver it has to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c b/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c deleted file mode 100644 index a19a46770c2b..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c +++ /dev/null @@ -1,440 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Support for audio capture for tm5600/6000/6010 -// Copyright (c) 2007-2008 Mauro Carvalho Chehab <mchehab@kernel.org> -// -// Based on cx88-alsa.c - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/usb.h> -#include <linux/slab.h> - -#include <linux/delay.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/control.h> -#include <sound/initval.h> - - -#include "tm6000.h" -#include "tm6000-regs.h" - -#undef dprintk - -#define dprintk(level, fmt, arg...) do { \ - if (debug >= level) \ - printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \ - } while (0) - -/**************************************************************************** - Module global static vars - ****************************************************************************/ - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ - -static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; - -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled."); - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s)."); - - -/**************************************************************************** - Module macros - ****************************************************************************/ - -MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL v2"); -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages"); - -/**************************************************************************** - Module specific functions - ****************************************************************************/ - -/* - * BOARD Specific: Sets audio DMA - */ - -static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) -{ - struct tm6000_core *core = chip->core; - - dprintk(1, "Starting audio DMA\n"); - - /* Enables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40); - - tm6000_set_audio_bitrate(core, 48000); - - return 0; -} - -/* - * BOARD Specific: Resets audio DMA - */ -static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip) -{ - struct tm6000_core *core = chip->core; - - dprintk(1, "Stopping audio DMA\n"); - - /* Disables audio */ - tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40); - - return 0; -} - -/**************************************************************************** - ALSA PCM Interface - ****************************************************************************/ - -/* - * Digital hardware definition - */ -#define DEFAULT_FIFO_SIZE 4096 - -static const struct snd_pcm_hardware snd_tm6000_digital_hw = { - .info = SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .period_bytes_min = 64, - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98, - .buffer_bytes_max = 62720 * 8, -}; - -/* - * audio pcm capture open callback - */ -static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - err = snd_pcm_hw_constraint_pow2(runtime, 0, - SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) - goto _error; - - chip->substream = substream; - - runtime->hw = snd_tm6000_digital_hw; - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - - return 0; -_error: - dprintk(1, "Error opening PCM!\n"); - return err; -} - -/* - * audio close callback - */ -static int snd_tm6000_close(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - - if (atomic_read(&core->stream_started) > 0) { - atomic_set(&core->stream_started, 0); - schedule_work(&core->wq_trigger); - } - - return 0; -} - -static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size) -{ - struct snd_tm6000_card *chip = core->adev; - struct snd_pcm_substream *substream = chip->substream; - struct snd_pcm_runtime *runtime; - int period_elapsed = 0; - unsigned int stride, buf_pos; - int length; - - if (atomic_read(&core->stream_started) == 0) - return 0; - - if (!size || !substream) { - dprintk(1, "substream was NULL\n"); - return -EINVAL; - } - - runtime = substream->runtime; - if (!runtime || !runtime->dma_area) { - dprintk(1, "runtime was NULL\n"); - return -EINVAL; - } - - buf_pos = chip->buf_pos; - stride = runtime->frame_bits >> 3; - - if (stride == 0) { - dprintk(1, "stride is zero\n"); - return -EINVAL; - } - - length = size / stride; - if (length == 0) { - dprintk(1, "%s: length was zero\n", __func__); - return -EINVAL; - } - - dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size, - runtime->dma_area, buf_pos, - (unsigned int)runtime->buffer_size, stride); - - if (buf_pos + length >= runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - buf_pos; - memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride); - memcpy(runtime->dma_area, buf + cnt * stride, - length * stride - cnt * stride); - } else - memcpy(runtime->dma_area + buf_pos * stride, buf, - length * stride); - - snd_pcm_stream_lock(substream); - - chip->buf_pos += length; - if (chip->buf_pos >= runtime->buffer_size) - chip->buf_pos -= runtime->buffer_size; - - chip->period_pos += length; - if (chip->period_pos >= runtime->period_size) { - chip->period_pos -= runtime->period_size; - period_elapsed = 1; - } - - snd_pcm_stream_unlock(substream); - - if (period_elapsed) - snd_pcm_period_elapsed(substream); - - return 0; -} - -/* - * prepare callback - */ -static int snd_tm6000_prepare(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - chip->buf_pos = 0; - chip->period_pos = 0; - - return 0; -} - - -/* - * trigger callback - */ -static void audio_trigger(struct work_struct *work) -{ - struct tm6000_core *core = container_of(work, struct tm6000_core, - wq_trigger); - struct snd_tm6000_card *chip = core->adev; - - if (atomic_read(&core->stream_started)) { - dprintk(1, "starting capture"); - _tm6000_start_audio_dma(chip); - } else { - dprintk(1, "stopping capture"); - _tm6000_stop_audio_dma(chip); - } -} - -static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - struct tm6000_core *core = chip->core; - int err = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - atomic_set(&core->stream_started, 1); - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&core->stream_started, 0); - break; - default: - err = -EINVAL; - break; - } - schedule_work(&core->wq_trigger); - - return err; -} -/* - * pointer callback - */ -static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream) -{ - struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream); - - return chip->buf_pos; -} - -/* - * operators - */ -static const struct snd_pcm_ops snd_tm6000_pcm_ops = { - .open = snd_tm6000_pcm_open, - .close = snd_tm6000_close, - .prepare = snd_tm6000_prepare, - .trigger = snd_tm6000_card_trigger, - .pointer = snd_tm6000_pointer, -}; - -/* - * create a PCM device - */ - -/* FIXME: Control interface - How to control volume/mute? */ - -/**************************************************************************** - Basic Flow for Sound Devices - ****************************************************************************/ - -/* - * Alsa Constructor - Component probe - */ -static int tm6000_audio_init(struct tm6000_core *dev) -{ - struct snd_card *card; - struct snd_tm6000_card *chip; - int rc; - static int devnr; - char component[14]; - struct snd_pcm *pcm; - - if (!dev) - return 0; - - if (devnr >= SNDRV_CARDS) - return -ENODEV; - - if (!enable[devnr]) - return -ENOENT; - - rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000", - THIS_MODULE, 0, &card); - if (rc < 0) { - snd_printk(KERN_ERR "cannot create card instance %d\n", devnr); - return rc; - } - strscpy(card->driver, "tm6000-alsa", sizeof(card->driver)); - strscpy(card->shortname, "TM5600/60x0", sizeof(card->shortname)); - sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d", - dev->udev->bus->busnum, dev->udev->devnum); - - sprintf(component, "USB%04x:%04x", - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct)); - snd_component_add(card, component); - - chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL); - if (!chip) { - rc = -ENOMEM; - goto error; - } - - chip->core = dev; - chip->card = card; - dev->adev = chip; - spin_lock_init(&chip->reg_lock); - - rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm); - if (rc < 0) - goto error_chip; - - pcm->info_flags = 0; - pcm->private_data = chip; - strscpy(pcm->name, "Trident TM5600/60x0", sizeof(pcm->name)); - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops); - snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); - - INIT_WORK(&dev->wq_trigger, audio_trigger); - rc = snd_card_register(card); - if (rc < 0) - goto error_chip; - - dprintk(1, "Registered audio driver for %s\n", card->longname); - - return 0; - -error_chip: - kfree(chip); - dev->adev = NULL; -error: - snd_card_free(card); - return rc; -} - -static int tm6000_audio_fini(struct tm6000_core *dev) -{ - struct snd_tm6000_card *chip; - - if (!dev) - return 0; - chip = dev->adev; - - if (!chip) - return 0; - - if (!chip->card) - return 0; - - snd_card_free(chip->card); - chip->card = NULL; - kfree(chip); - dev->adev = NULL; - - return 0; -} - -static struct tm6000_ops audio_ops = { - .type = TM6000_AUDIO, - .name = "TM6000 Audio Extension", - .init = tm6000_audio_init, - .fini = tm6000_audio_fini, - .fillbuf = tm6000_fillbuf, -}; - -static int __init tm6000_alsa_register(void) -{ - return tm6000_register_extension(&audio_ops); -} - -static void __exit tm6000_alsa_unregister(void) -{ - tm6000_unregister_extension(&audio_ops); -} - -module_init(tm6000_alsa_register); -module_exit(tm6000_alsa_unregister); diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-cards.c b/drivers/staging/media/deprecated/tm6000/tm6000-cards.c deleted file mode 100644 index 98f4a63adc2a..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-cards.c +++ /dev/null @@ -1,1397 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices -// -// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/usb.h> -#include <linux/slab.h> -#include <media/v4l2-common.h> -#include <media/tuner.h> -#include <media/i2c/tvaudio.h> -#include <media/rc-map.h> - -#include "tm6000.h" -#include "tm6000-regs.h" -#include "xc2028.h" -#include "xc5000.h" - -#define TM6000_BOARD_UNKNOWN 0 -#define TM5600_BOARD_GENERIC 1 -#define TM6000_BOARD_GENERIC 2 -#define TM6010_BOARD_GENERIC 3 -#define TM5600_BOARD_10MOONS_UT821 4 -#define TM5600_BOARD_10MOONS_UT330 5 -#define TM6000_BOARD_ADSTECH_DUAL_TV 6 -#define TM6000_BOARD_FREECOM_AND_SIMILAR 7 -#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8 -#define TM6010_BOARD_HAUPPAUGE_900H 9 -#define TM6010_BOARD_BEHOLD_WANDER 10 -#define TM6010_BOARD_BEHOLD_VOYAGER 11 -#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12 -#define TM6010_BOARD_TWINHAN_TU501 13 -#define TM6010_BOARD_BEHOLD_WANDER_LITE 14 -#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15 -#define TM5600_BOARD_TERRATEC_GRABSTER 16 - -#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \ - (model == TM5600_BOARD_GENERIC) || \ - (model == TM6000_BOARD_GENERIC) || \ - (model == TM6010_BOARD_GENERIC)) - -#define TM6000_MAXBOARDS 16 -static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; - -module_param_array(card, int, NULL, 0444); - -static unsigned long tm6000_devused; - - -struct tm6000_board { - char *name; - char eename[16]; /* EEPROM name */ - unsigned eename_size; /* size of EEPROM name */ - unsigned eename_pos; /* Position where it appears at ROM */ - - struct tm6000_capabilities caps; - - enum tm6000_devtype type; /* variant of the chipset */ - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - int demod_addr; /* demodulator address */ - - struct tm6000_gpio gpio; - - struct tm6000_input vinput[3]; - struct tm6000_input rinput; - - char *ir_codes; -}; - -static struct tm6000_board tm6000_boards[] = { - [TM6000_BOARD_UNKNOWN] = { - .name = "Unknown tm6000 video grabber", - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM5600_BOARD_GENERIC] = { - .name = "Generic tm5600 board", - .type = TM5600, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_GENERIC] = { - .name = "Generic tm6000 board", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_GENERIC] = { - .name = "Generic tm6010 board", - .type = TM6010, - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM5600_BOARD_10MOONS_UT821] = { - .name = "10Moons UT 821", - .tuner_type = TUNER_XC2028, - .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b}, - .eename_size = 14, - .eename_pos = 0x14, - .type = TM5600, - .tuner_addr = 0xc2 >> 1, - .caps = { - .has_tuner = 1, - .has_eeprom = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM5600_BOARD_10MOONS_UT330] = { - .name = "10Moons UT 330", - .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4, - .tuner_addr = 0xc8 >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_ADSTECH_DUAL_TV] = { - .name = "ADSTECH Dual TV USB", - .tuner_type = TUNER_XC2028, - .tuner_addr = 0xc8 >> 1, - .caps = { - .has_tuner = 1, - .has_tda9874 = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_FREECOM_AND_SIMILAR] = { - .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 0, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_4, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = { - .name = "ADSTECH Mini Dual TV USB", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc8 >> 1, - .demod_addr = 0x1e >> 1, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 0, - }, - .gpio = { - .tuner_reset = TM6000_GPIO_4, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_HAUPPAUGE_900H] = { - .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick", - .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 }, - .eename_size = 14, - .eename_pos = 0x42, - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .ir_codes = RC_MAP_HAUPPAUGE, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_BEHOLD_WANDER] = { - .name = "Beholder Wander DVB-T/TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .demod_reset = TM6010_GPIO_1, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, - [TM6010_BOARD_BEHOLD_VOYAGER] = { - .name = "Beholder Voyager TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - .has_remote = 1, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, - [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = { - .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_SIF1, - }, - }, - [TM5600_BOARD_TERRATEC_GRABSTER] = { - .name = "Terratec Grabster AV 150/250 MX", - .type = TM5600, - .tuner_type = TUNER_ABSENT, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_ADC1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_TWINHAN_TU501] = { - .name = "Twinhan TU501(704D1)", - .tuner_type = TUNER_XC2028, /* has a XC3028 */ - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_2, - .tuner_on = TM6010_GPIO_3, - .demod_reset = TM6010_GPIO_1, - .demod_on = TM6010_GPIO_4, - .power_led = TM6010_GPIO_7, - .dvb_led = TM6010_GPIO_5, - .ir = TM6010_GPIO_0, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, { - .type = TM6000_INPUT_COMPOSITE1, - .vmux = TM6000_VMUX_VIDEO_A, - .amux = TM6000_AMUX_ADC2, - }, { - .type = TM6000_INPUT_SVIDEO, - .vmux = TM6000_VMUX_VIDEO_AB, - .amux = TM6000_AMUX_ADC2, - }, - }, - }, - [TM6010_BOARD_BEHOLD_WANDER_LITE] = { - .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .demod_addr = 0x1e >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 0, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .demod_reset = TM6010_GPIO_1, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, - [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = { - .name = "Beholder Voyager Lite TV/FM USB2.0", - .tuner_type = TUNER_XC5000, - .tuner_addr = 0xc2 >> 1, - .type = TM6010, - .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - .has_remote = 0, - .has_radio = 1, - }, - .gpio = { - .tuner_reset = TM6010_GPIO_0, - .power_led = TM6010_GPIO_6, - }, - .vinput = { { - .type = TM6000_INPUT_TV, - .vmux = TM6000_VMUX_VIDEO_B, - .amux = TM6000_AMUX_SIF1, - }, - }, - .rinput = { - .type = TM6000_INPUT_RADIO, - .amux = TM6000_AMUX_ADC1, - }, - }, -}; - -/* table of devices that work with this driver */ -static const struct usb_device_id tm6000_id_table[] = { - { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC }, - { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, - { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, - { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR }, - { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV }, - { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H }, - { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER }, - { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, - { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, - { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, - { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER }, - { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, - { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, - { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, - { } -}; -MODULE_DEVICE_TABLE(usb, tm6000_id_table); - -/* Control power led for show some activity */ -void tm6000_flash_led(struct tm6000_core *dev, u8 state) -{ - /* Power LED unconfigured */ - if (!dev->gpio.power_led) - return; - - /* ON Power LED */ - if (state) { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - break; - } - } - /* OFF Power LED */ - else { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - break; - } - } -} - -/* Tuner callback to provide the proper gpio changes needed for xc5000 */ -int tm6000_xc5000_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct tm6000_core *dev = ptr; - - if (dev->tuner_type != TUNER_XC5000) - return 0; - - switch (command) { - case XC5000_TUNER_RESET: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(15); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(15); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - break; - } - return rc; -} -EXPORT_SYMBOL_GPL(tm6000_xc5000_callback); - -/* Tuner callback to provide the proper gpio changes needed for xc2028 */ - -int tm6000_tuner_callback(void *ptr, int component, int command, int arg) -{ - int rc = 0; - struct tm6000_core *dev = ptr; - - if (dev->tuner_type != TUNER_XC2028) - return 0; - - switch (command) { - case XC2028_RESET_CLK: - tm6000_ir_wait(dev, 0); - - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, - 0x02, arg); - msleep(10); - rc = tm6000_i2c_reset(dev, 10); - break; - case XC2028_TUNER_RESET: - /* Reset codes during load firmware */ - switch (arg) { - case 0: - /* newer tuner can faster reset */ - switch (dev->model) { - case TM5600_BOARD_10MOONS_UT821: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x01); - msleep(10); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x00); - msleep(10); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - 0x300, 0x01); - break; - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(60); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(75); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(60); - break; - default: - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - msleep(130); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - msleep(130); - break; - } - - tm6000_ir_wait(dev, 1); - break; - case 1: - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, - 0x02, 0x01); - msleep(10); - break; - case 2: - rc = tm6000_i2c_reset(dev, 100); - break; - } - break; - case XC2028_I2C_FLUSH: - tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); - tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); - break; - } - return rc; -} -EXPORT_SYMBOL_GPL(tm6000_tuner_callback); - -int tm6000_cards_setup(struct tm6000_core *dev) -{ - /* - * Board-specific initialization sequence. Handles all GPIO - * initialization sequences that are board-specific. - * Up to now, all found devices use GPIO1 and GPIO4 at the same way. - * Probably, they're all based on some reference device. Due to that, - * there's a common routine at the end to handle those GPIO's. Devices - * that use different pinups or init sequences can just return at - * the board-specific session. - */ - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - case TM6010_BOARD_GENERIC: - /* Turn xceive 3028 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01); - msleep(15); - /* Turn zarlink zl10353 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); - msleep(15); - /* Reset zarlink zl10353 */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); - msleep(15); - /* Turn zarlink zl10353 off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01); - msleep(15); - /* ir ? */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01); - msleep(15); - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); - msleep(15); - /* DVB led off (orange) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01); - msleep(15); - /* Turn zarlink zl10353 on */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); - msleep(15); - /* Reset zarlink zl10353 */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - /* Power led on (blue) */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); - msleep(15); - break; - default: - break; - } - - /* - * Default initialization. Most of the devices seem to use GPIO1 - * and GPIO4.on the same way, so, this handles the common sequence - * used by most devices. - * If a device uses a different sequence or different GPIO pins for - * reset, just add the code at the board-specific part - */ - - if (dev->gpio.tuner_reset) { - int rc; - int i; - - for (i = 0; i < 2; i++) { - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x00); - if (rc < 0) { - printk(KERN_ERR "Error %i doing tuner reset\n", rc); - return rc; - } - - msleep(10); /* Just to be conservative */ - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.tuner_reset, 0x01); - if (rc < 0) { - printk(KERN_ERR "Error %i doing tuner reset\n", rc); - return rc; - } - } - } else { - printk(KERN_ERR "Tuner reset is not configured\n"); - return -1; - } - - msleep(50); - - return 0; -}; - -static void tm6000_config_tuner(struct tm6000_core *dev) -{ - struct tuner_setup tun_setup; - - /* Load tuner module */ - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tuner", dev->tuner_addr, NULL); - - memset(&tun_setup, 0, sizeof(tun_setup)); - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - tun_setup.mode_mask = 0; - if (dev->caps.has_tuner) - tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); - - switch (dev->tuner_type) { - case TUNER_XC2028: - tun_setup.tuner_callback = tm6000_tuner_callback; - break; - case TUNER_XC5000: - tun_setup.tuner_callback = tm6000_xc5000_callback; - break; - } - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); - - switch (dev->tuner_type) { - case TUNER_XC2028: { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); - memset(&ctl, 0, sizeof(ctl)); - - ctl.demod = XC3028_FE_ZARLINK456; - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - ctl.max_len = 80; - ctl.fname = "xc3028L-v36.fw"; - break; - default: - if (dev->dev_type == TM6010) - ctl.fname = "xc3028-v27.fw"; - else - ctl.fname = "xc3028-v24.fw"; - } - - printk(KERN_INFO "Setting firmware parameters for xc2028\n"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, - &xc2028_cfg); - - } - break; - case TUNER_XC5000: - { - struct v4l2_priv_tun_config xc5000_cfg; - struct xc5000_config ctl = { - .i2c_address = dev->tuner_addr, - .if_khz = 4570, - .radio_input = XC5000_RADIO_FM1_MONO, - }; - - xc5000_cfg.tuner = TUNER_XC5000; - xc5000_cfg.priv = &ctl; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, - &xc5000_cfg); - } - break; - default: - printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n"); - break; - } -} - -static int fill_board_specific_data(struct tm6000_core *dev) -{ - int rc; - - dev->dev_type = tm6000_boards[dev->model].type; - dev->tuner_type = tm6000_boards[dev->model].tuner_type; - dev->tuner_addr = tm6000_boards[dev->model].tuner_addr; - - dev->gpio = tm6000_boards[dev->model].gpio; - - dev->ir_codes = tm6000_boards[dev->model].ir_codes; - - dev->demod_addr = tm6000_boards[dev->model].demod_addr; - - dev->caps = tm6000_boards[dev->model].caps; - - dev->vinput[0] = tm6000_boards[dev->model].vinput[0]; - dev->vinput[1] = tm6000_boards[dev->model].vinput[1]; - dev->vinput[2] = tm6000_boards[dev->model].vinput[2]; - dev->rinput = tm6000_boards[dev->model].rinput; - - /* setup per-model quirks */ - switch (dev->model) { - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_HAUPPAUGE_900H: - dev->quirks |= TM6000_QUIRK_NO_USB_DELAY; - break; - - default: - break; - } - - /* initialize hardware */ - rc = tm6000_init(dev); - if (rc < 0) - return rc; - - return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev); -} - - -static void use_alternative_detection_method(struct tm6000_core *dev) -{ - int i, model = -1; - - if (!dev->eedata_size) - return; - - for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) { - if (!tm6000_boards[i].eename_size) - continue; - if (dev->eedata_size < tm6000_boards[i].eename_pos + - tm6000_boards[i].eename_size) - continue; - - if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos], - tm6000_boards[i].eename, - tm6000_boards[i].eename_size)) { - model = i; - break; - } - } - if (model < 0) { - printk(KERN_INFO "Device has eeprom but is currently unknown\n"); - return; - } - - dev->model = model; - - printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n", - tm6000_boards[model].name, model); -} - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct tm6000_core *dev = container_of(work, struct tm6000_core, - request_module_wk); - - request_module("tm6000-alsa"); - - if (dev->caps.has_dvb) - request_module("tm6000-dvb"); -} - -static void request_modules(struct tm6000_core *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct tm6000_core *dev) -{ - flush_work(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - -static int tm6000_init_dev(struct tm6000_core *dev) -{ - struct v4l2_frequency f; - int rc = 0; - - mutex_init(&dev->lock); - mutex_lock(&dev->lock); - - if (!is_generic(dev->model)) { - rc = fill_board_specific_data(dev); - if (rc < 0) - goto err; - - /* register i2c bus */ - rc = tm6000_i2c_register(dev); - if (rc < 0) - goto err; - } else { - /* register i2c bus */ - rc = tm6000_i2c_register(dev); - if (rc < 0) - goto err; - - use_alternative_detection_method(dev); - - rc = fill_board_specific_data(dev); - if (rc < 0) - goto err; - } - - /* Default values for STD and resolutions */ - dev->width = 720; - dev->height = 480; - dev->norm = V4L2_STD_NTSC_M; - - /* Configure tuner */ - tm6000_config_tuner(dev); - - /* Set video standard */ - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); - - /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 3092; /* 193.25 MHz */ - dev->freq = f.frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); - - if (dev->caps.has_tda9874) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, - "tvaudio", I2C_ADDR_TDA9874, NULL); - - /* register and initialize V4L2 */ - rc = tm6000_v4l2_register(dev); - if (rc < 0) - goto err; - - tm6000_add_into_devlist(dev); - tm6000_init_extension(dev); - - tm6000_ir_init(dev); - - request_modules(dev); - - mutex_unlock(&dev->lock); - return 0; - -err: - mutex_unlock(&dev->lock); - return rc; -} - -/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ -#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) - -static void get_max_endpoint(struct usb_device *udev, - struct usb_host_interface *alt, - char *msgtype, - struct usb_host_endpoint *curr_e, - struct tm6000_endpoint *tm_ep) -{ - u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize); - unsigned int size = tmp & 0x7ff; - - if (udev->speed == USB_SPEED_HIGH) - size = size * hb_mult(tmp); - - if (size > tm_ep->maxsize) { - tm_ep->endp = curr_e; - tm_ep->maxsize = size; - tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber; - tm_ep->bAlternateSetting = alt->desc.bAlternateSetting; - - printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n", - msgtype, curr_e->desc.bEndpointAddress, - size); - } -} - -/* - * tm6000_usb_probe() - * checks for supported devices - */ -static int tm6000_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev; - struct tm6000_core *dev; - int i, rc; - int nr = 0; - char *speed; - - usbdev = usb_get_dev(interface_to_usbdev(interface)); - - /* Selects the proper interface */ - rc = usb_set_interface(usbdev, 0, 1); - if (rc < 0) - goto report_failure; - - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); - if (nr >= TM6000_MAXBOARDS) { - printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); - rc = -ENOMEM; - goto put_device; - } - - /* Create and initialize dev struct */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - rc = -ENOMEM; - goto put_device; - } - spin_lock_init(&dev->slock); - mutex_init(&dev->usb_lock); - - /* Increment usage count */ - set_bit(nr, &tm6000_devused); - snprintf(dev->name, 29, "tm6000 #%d", nr); - - dev->model = id->driver_info; - if (card[nr] < ARRAY_SIZE(tm6000_boards)) - dev->model = card[nr]; - - dev->udev = usbdev; - dev->devno = nr; - - switch (usbdev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } - - /* Get endpoints */ - for (i = 0; i < interface->num_altsetting; i++) { - int ep; - - for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { - struct usb_host_endpoint *e; - int dir_out; - - e = &interface->altsetting[i].endpoint[ep]; - - dir_out = ((e->desc.bEndpointAddress & - USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); - - printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n", - i, - interface->altsetting[i].desc.bInterfaceNumber, - interface->altsetting[i].desc.bInterfaceClass); - - switch (e->desc.bmAttributes) { - case USB_ENDPOINT_XFER_BULK: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "Bulk IN", e, - &dev->bulk_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "Bulk OUT", e, - &dev->bulk_out); - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "ISOC IN", e, - &dev->isoc_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "ISOC OUT", e, - &dev->isoc_out); - } - break; - case USB_ENDPOINT_XFER_INT: - if (!dir_out) { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "INT IN", e, - &dev->int_in); - } else { - get_max_endpoint(usbdev, - &interface->altsetting[i], - "INT OUT", e, - &dev->int_out); - } - break; - } - } - } - - - printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n", - speed, - le16_to_cpu(dev->udev->descriptor.idVendor), - le16_to_cpu(dev->udev->descriptor.idProduct), - interface->altsetting->desc.bInterfaceNumber); - -/* check if the the device has the iso in endpoint at the correct place */ - if (!dev->isoc_in.endp) { - printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); - rc = -ENODEV; - goto free_device; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name); - - rc = tm6000_init_dev(dev); - if (rc < 0) - goto free_device; - - return 0; - -free_device: - kfree(dev); -report_failure: - printk(KERN_ERR "tm6000: Error %d while registering\n", rc); - - clear_bit(nr, &tm6000_devused); -put_device: - usb_put_dev(usbdev); - return rc; -} - -/* - * tm6000_usb_disconnect() - * called when the device gets disconnected - * video device will be unregistered on v4l2_close in case it is still open - */ -static void tm6000_usb_disconnect(struct usb_interface *interface) -{ - struct tm6000_core *dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - if (!dev) - return; - - printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); - - flush_request_modules(dev); - - tm6000_ir_fini(dev); - - if (dev->gpio.power_led) { - switch (dev->model) { - case TM6010_BOARD_HAUPPAUGE_900H: - case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: - case TM6010_BOARD_TWINHAN_TU501: - /* Power led off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x01); - msleep(15); - break; - case TM6010_BOARD_BEHOLD_WANDER: - case TM6010_BOARD_BEHOLD_VOYAGER: - case TM6010_BOARD_BEHOLD_WANDER_LITE: - case TM6010_BOARD_BEHOLD_VOYAGER_LITE: - /* Power led off */ - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.power_led, 0x00); - msleep(15); - break; - } - } - tm6000_v4l2_unregister(dev); - - tm6000_i2c_unregister(dev); - - v4l2_device_unregister(&dev->v4l2_dev); - - dev->state |= DEV_DISCONNECTED; - - usb_put_dev(dev->udev); - - tm6000_close_extension(dev); - tm6000_remove_from_devlist(dev); - - clear_bit(dev->devno, &tm6000_devused); - kfree(dev); -} - -static struct usb_driver tm6000_usb_driver = { - .name = "tm6000", - .probe = tm6000_usb_probe, - .disconnect = tm6000_usb_disconnect, - .id_table = tm6000_id_table, -}; - -module_usb_driver(tm6000_usb_driver); - -MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter"); -MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-core.c b/drivers/staging/media/deprecated/tm6000/tm6000-core.c deleted file mode 100644 index 5c8cbc5d6f72..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-core.c +++ /dev/null @@ -1,916 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices -// -// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> -// -// Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com> -// - DVB-T support - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/i2c.h> -#include "tm6000.h" -#include "tm6000-regs.h" -#include <media/v4l2-common.h> -#include <media/tuner.h> - -#define USB_TIMEOUT (5 * HZ) /* ms */ - -int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, - u16 value, u16 index, u8 *buf, u16 len) -{ - int ret, i; - unsigned int pipe; - u8 *data = NULL; - int delay = 5000; - - if (len) { - data = kzalloc(len, GFP_KERNEL); - if (!data) - return -ENOMEM; - } - - mutex_lock(&dev->usb_lock); - - if (req_type & USB_DIR_IN) - pipe = usb_rcvctrlpipe(dev->udev, 0); - else { - pipe = usb_sndctrlpipe(dev->udev, 0); - memcpy(data, buf, len); - } - - if (tm6000_debug & V4L2_DEBUG_I2C) { - printk(KERN_DEBUG "(dev %p, pipe %08x): ", dev->udev, pipe); - - printk(KERN_CONT "%s: %02x %02x %02x %02x %02x %02x %02x %02x ", - (req_type & USB_DIR_IN) ? " IN" : "OUT", - req_type, req, value&0xff, value>>8, index&0xff, - index>>8, len&0xff, len>>8); - - if (!(req_type & USB_DIR_IN)) { - printk(KERN_CONT ">>> "); - for (i = 0; i < len; i++) - printk(KERN_CONT " %02x", buf[i]); - printk(KERN_CONT "\n"); - } - } - - ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, - data, len, USB_TIMEOUT); - - if (req_type & USB_DIR_IN) - memcpy(buf, data, len); - - if (tm6000_debug & V4L2_DEBUG_I2C) { - if (ret < 0) { - if (req_type & USB_DIR_IN) - printk(KERN_DEBUG "<<< (len=%d)\n", len); - - printk(KERN_CONT "%s: Error #%d\n", __func__, ret); - } else if (req_type & USB_DIR_IN) { - printk(KERN_CONT "<<< "); - for (i = 0; i < len; i++) - printk(KERN_CONT " %02x", buf[i]); - printk(KERN_CONT "\n"); - } - } - - kfree(data); - - if (dev->quirks & TM6000_QUIRK_NO_USB_DELAY) - delay = 0; - - if (req == REQ_16_SET_GET_I2C_WR1_RDN && !(req_type & USB_DIR_IN)) { - unsigned int tsleep; - /* Calculate delay time, 14000us for 64 bytes */ - tsleep = (len * 200) + 200; - if (tsleep < delay) - tsleep = delay; - usleep_range(tsleep, tsleep + 1000); - } - else if (delay) - usleep_range(delay, delay + 1000); - - mutex_unlock(&dev->usb_lock); - return ret; -} - -int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - return - tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, - req, value, index, NULL, 0); -} -EXPORT_SYMBOL_GPL(tm6000_set_reg); - -int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[1]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 1); - - if (rc < 0) - return rc; - - return *buf; -} -EXPORT_SYMBOL_GPL(tm6000_get_reg); - -int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, - u16 index, u16 mask) -{ - int rc; - u8 buf[1]; - u8 new_index; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, 0, buf, 1); - - if (rc < 0) - return rc; - - new_index = (buf[0] & ~mask) | (index & mask); - - if (new_index == buf[0]) - return 0; - - return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, - req, value, new_index, NULL, 0); -} -EXPORT_SYMBOL_GPL(tm6000_set_reg_mask); - -int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[2]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 2); - - if (rc < 0) - return rc; - - return buf[1]|buf[0]<<8; -} - -int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index) -{ - int rc; - u8 buf[4]; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 4); - - if (rc < 0) - return rc; - - return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24; -} - -int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep) -{ - int rc; - - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0); - if (rc < 0) - return rc; - - msleep(tsleep); - - rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1); - msleep(tsleep); - - return rc; -} - -void tm6000_set_fourcc_format(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - int val; - - val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, 0) & 0xfc; - if (dev->fourcc == V4L2_PIX_FMT_UYVY) - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val); - else - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_IF, val | 1); - } else { - if (dev->fourcc == V4L2_PIX_FMT_UYVY) - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); - else - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90); - } -} - -static void tm6000_set_vbi(struct tm6000_core *dev) -{ - /* - * FIXME: - * VBI lines and start/end are different between 60Hz and 50Hz - * So, it is very likely that we need to change the config to - * something that takes it into account, doing something different - * if (dev->norm & V4L2_STD_525_60) - */ - - if (dev->dev_type == TM6010) { - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27); - tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55); - tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66); - tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66); - tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66); - tm6000_set_reg(dev, - TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01); - tm6000_set_reg(dev, - TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00); - tm6000_set_reg(dev, - TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02); - tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35); - tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0); - tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11); - tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c); - tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01); - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); - } -} - -int tm6000_init_analog_mode(struct tm6000_core *dev) -{ - struct v4l2_frequency f; - - if (dev->dev_type == TM6010) { - u8 active = TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE; - - if (!dev->radio) - active |= TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE; - - /* Enable video and audio */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, - active, 0x60); - /* Disable TS input */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, - 0x00, 0x40); - } else { - /* Enables soft reset */ - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - - if (dev->scaler) - /* Disable Hfilter and Enable TS Drop err */ - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20); - else /* Enable Hfilter and disable TS Drop err */ - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80); - - tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88); - tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23); - tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0); - tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06); - tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f); - - /* AP Software reset */ - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); - - tm6000_set_fourcc_format(dev); - - /* Disables soft reset */ - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); - } - msleep(20); - - /* Tuner firmware can now be loaded */ - - /* - * FIXME: This is a hack! xc3028 "sleeps" when no channel is detected - * for more than a few seconds. Not sure why, as this behavior does - * not happen on other devices with xc3028. So, I suspect that it - * is yet another bug at tm6000. After start sleeping, decoding - * doesn't start automatically. Instead, it requires some - * I2C commands to wake it up. As we want to have image at the - * beginning, we needed to add this hack. The better would be to - * discover some way to make tm6000 to wake up without this hack. - */ - f.frequency = dev->freq; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); - - msleep(100); - tm6000_set_standard(dev); - tm6000_set_vbi(dev); - tm6000_set_audio_bitrate(dev, 48000); - - /* switch dvb led off */ - if (dev->gpio.dvb_led) { - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.dvb_led, 0x01); - } - - return 0; -} - -int tm6000_init_digital_mode(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - /* Disable video and audio */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_IF, - 0x00, 0x60); - /* Enable TS input */ - tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, - 0x40, 0x40); - /* all power down, but not the digital data port */ - tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28); - tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc); - tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff); - } else { - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); - tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); - tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08); - tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); - tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40); - tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); - tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09); - tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37); - tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8); - tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0); - tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60); - - tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); - tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08); - msleep(50); - - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); - msleep(50); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01); - msleep(50); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); - msleep(100); - } - - /* switch dvb led on */ - if (dev->gpio.dvb_led) { - tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, - dev->gpio.dvb_led, 0x00); - } - - return 0; -} -EXPORT_SYMBOL(tm6000_init_digital_mode); - -struct reg_init { - u8 req; - u8 reg; - u8 val; -}; - -/* The meaning of those initializations are unknown */ -static struct reg_init tm6000_init_tab[] = { - /* REG VALUE */ - { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f }, - { TM6010_REQ07_RFF_SOFT_RESET, 0x08 }, - { TM6010_REQ07_RFF_SOFT_RESET, 0x00 }, - { TM6010_REQ07_RD5_POWERSAVE, 0x4f }, - { TM6000_REQ07_RDA_CLK_SEL, 0x23 }, - { TM6000_REQ07_RDB_OUT_SEL, 0x08 }, - { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 }, - { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 }, - { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 }, - { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 }, - { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 }, /* 48000 bits/sample, external input */ - { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 }, - - { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */ - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, - { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, - { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, - { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, - { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, - { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, - { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, - { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, - { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, - { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, - { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, - { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, - { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, - { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, - { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, - { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, - { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, - { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, - { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, - { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, - { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, - { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, - { TM6010_REQ07_RC3_HSTART1, 0x88 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, /* End of the soft reset */ - { TM6010_REQ05_R18_IMASK7, 0x00 }, -}; - -static struct reg_init tm6010_init_tab[] = { - { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 }, - { TM6010_REQ07_RC4_HSTART0, 0xa0 }, - { TM6010_REQ07_RC6_HEND0, 0x40 }, - { TM6010_REQ07_RCA_VEND0, 0x31 }, - { TM6010_REQ07_RCC_ACTIVE_IF, 0xe1 }, - { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 }, - { TM6010_REQ07_RFE_POWER_DOWN, 0x7f }, - - { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 }, - { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 }, - { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 }, - { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 }, - { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 }, - { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 }, - { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 }, - { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 }, - { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc }, - - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, - { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, - { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, - { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, - { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, - { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, - { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, - { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, - { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, - { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, - { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, - { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, - { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, - { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, - { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, - { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, - { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, - { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, - { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, - { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, - { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, - { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, - { TM6010_REQ07_RC3_HSTART1, 0x88 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - - { TM6010_REQ05_R18_IMASK7, 0x00 }, - - { TM6010_REQ07_RDC_IR_LEADER1, 0xaa }, - { TM6010_REQ07_RDD_IR_LEADER0, 0x30 }, - { TM6010_REQ07_RDE_IR_PULSE_CNT1, 0x20 }, - { TM6010_REQ07_RDF_IR_PULSE_CNT0, 0xd0 }, - { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 }, - { TM6010_REQ07_RD8_IR, 0x0f }, - - /* set remote wakeup key:any key wakeup */ - { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe }, - { TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff }, -}; - -int tm6000_init(struct tm6000_core *dev) -{ - int board, rc = 0, i, size; - struct reg_init *tab; - - /* Check board revision */ - board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0); - if (board >= 0) { - switch (board & 0xff) { - case 0xf3: - printk(KERN_INFO "Found tm6000\n"); - if (dev->dev_type != TM6000) - dev->dev_type = TM6000; - break; - case 0xf4: - printk(KERN_INFO "Found tm6010\n"); - if (dev->dev_type != TM6010) - dev->dev_type = TM6010; - break; - default: - printk(KERN_INFO "Unknown board version = 0x%08x\n", board); - } - } else - printk(KERN_ERR "Error %i while retrieving board version\n", board); - - if (dev->dev_type == TM6010) { - tab = tm6010_init_tab; - size = ARRAY_SIZE(tm6010_init_tab); - } else { - tab = tm6000_init_tab; - size = ARRAY_SIZE(tm6000_init_tab); - } - - /* Load board's initialization table */ - for (i = 0; i < size; i++) { - rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val); - if (rc < 0) { - printk(KERN_ERR "Error %i while setting req %d, reg %d to value %d\n", - rc, - tab[i].req, tab[i].reg, tab[i].val); - return rc; - } - } - - msleep(5); /* Just to be conservative */ - - rc = tm6000_cards_setup(dev); - - return rc; -} - - -int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) -{ - int val = 0; - u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ - u8 areg_0a = 0x91; /* SIF 48KHz */ - - switch (bitrate) { - case 48000: - areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ - areg_0a = 0x91; /* SIF 48KHz */ - dev->audio_bitrate = bitrate; - break; - case 32000: - areg_f0 = 0x00; /* ADC MCLK = 375 Fs */ - areg_0a = 0x90; /* SIF 32KHz */ - dev->audio_bitrate = bitrate; - break; - default: - return -EINVAL; - } - - - /* enable I2S, if we use sif or external I2S device */ - if (dev->dev_type == TM6010) { - val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a); - if (val < 0) - return val; - - val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - areg_f0, 0xf0); - if (val < 0) - return val; - } else { - val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, - areg_f0, 0xf0); - if (val < 0) - return val; - } - return 0; -} -EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); - -int tm6000_set_audio_rinput(struct tm6000_core *dev) -{ - if (dev->dev_type == TM6010) { - /* Audio crossbar setting, default SIF1 */ - u8 areg_f0; - u8 areg_07 = 0x10; - - switch (dev->rinput.amux) { - case TM6000_AMUX_SIF1: - case TM6000_AMUX_SIF2: - areg_f0 = 0x03; - areg_07 = 0x30; - break; - case TM6000_AMUX_ADC1: - areg_f0 = 0x00; - break; - case TM6000_AMUX_ADC2: - areg_f0 = 0x08; - break; - case TM6000_AMUX_I2S: - areg_f0 = 0x04; - break; - default: - printk(KERN_INFO "%s: audio input doesn't support\n", - dev->name); - return 0; - break; - } - /* Set audio input crossbar */ - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - areg_f0, 0x0f); - /* Mux overflow workaround */ - tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, - areg_07, 0xf0); - } else { - u8 areg_eb; - /* Audio setting, default LINE1 */ - switch (dev->rinput.amux) { - case TM6000_AMUX_ADC1: - areg_eb = 0x00; - break; - case TM6000_AMUX_ADC2: - areg_eb = 0x04; - break; - default: - printk(KERN_INFO "%s: audio input doesn't support\n", - dev->name); - return 0; - break; - } - /* Set audio input */ - tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, - areg_eb, 0x0f); - } - return 0; -} - -static void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) -{ - u8 mute_reg = 0; - - if (mute) - mute_reg = 0x08; - - tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08); -} - -static void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute) -{ - u8 mute_reg = 0; - - if (mute) - mute_reg = 0x20; - - if (dev->dev_type == TM6010) { - tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, - mute_reg, 0x20); - tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, - mute_reg, 0x20); - } else { - tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, - mute_reg, 0x20); - tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, - mute_reg, 0x20); - } -} - -int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute) -{ - enum tm6000_mux mux; - - if (dev->radio) - mux = dev->rinput.amux; - else - mux = dev->vinput[dev->input].amux; - - switch (mux) { - case TM6000_AMUX_SIF1: - case TM6000_AMUX_SIF2: - if (dev->dev_type == TM6010) - tm6010_set_mute_sif(dev, mute); - else { - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has SIF audio inputs. Please check the %s configuration.\n", - dev->name); - return -EINVAL; - } - break; - case TM6000_AMUX_ADC1: - case TM6000_AMUX_ADC2: - tm6010_set_mute_adc(dev, mute); - break; - default: - return -EINVAL; - break; - } - return 0; -} - -static void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) -{ - u8 vol_reg; - - vol_reg = vol & 0x0F; - - if (vol < 0) - vol_reg |= 0x40; - - tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg); - tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg); -} - -static void tm6010_set_volume_adc(struct tm6000_core *dev, int vol) -{ - u8 vol_reg; - - vol_reg = (vol + 0x10) & 0x1f; - - if (dev->dev_type == TM6010) { - tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg); - tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg); - } else { - tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg); - tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg); - } -} - -void tm6000_set_volume(struct tm6000_core *dev, int vol) -{ - enum tm6000_mux mux; - - if (dev->radio) { - mux = dev->rinput.amux; - vol += 8; /* Offset to 0 dB */ - } else - mux = dev->vinput[dev->input].amux; - - switch (mux) { - case TM6000_AMUX_SIF1: - case TM6000_AMUX_SIF2: - if (dev->dev_type == TM6010) - tm6010_set_volume_sif(dev, vol); - else - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has SIF audio inputs. Please check the %s configuration.\n", - dev->name); - break; - case TM6000_AMUX_ADC1: - case TM6000_AMUX_ADC2: - tm6010_set_volume_adc(dev, vol); - break; - default: - break; - } -} - -static LIST_HEAD(tm6000_devlist); -static DEFINE_MUTEX(tm6000_devlist_mutex); - -/* - * tm6000_realease_resource() - */ - -void tm6000_remove_from_devlist(struct tm6000_core *dev) -{ - mutex_lock(&tm6000_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&tm6000_devlist_mutex); -}; - -void tm6000_add_into_devlist(struct tm6000_core *dev) -{ - mutex_lock(&tm6000_devlist_mutex); - list_add_tail(&dev->devlist, &tm6000_devlist); - mutex_unlock(&tm6000_devlist_mutex); -}; - -/* - * Extension interface - */ - -static LIST_HEAD(tm6000_extension_devlist); - -int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, - char *buf, int size) -{ - struct tm6000_ops *ops = NULL; - - /* FIXME: tm6000_extension_devlist_lock should be a spinlock */ - - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->fillbuf && ops->type == type) - ops->fillbuf(dev, buf, size); - } - - return 0; -} - -int tm6000_register_extension(struct tm6000_ops *ops) -{ - struct tm6000_core *dev = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_add_tail(&ops->next, &tm6000_extension_devlist); - list_for_each_entry(dev, &tm6000_devlist, devlist) { - ops->init(dev); - printk(KERN_INFO "%s: Initialized (%s) extension\n", - dev->name, ops->name); - } - mutex_unlock(&tm6000_devlist_mutex); - return 0; -} -EXPORT_SYMBOL(tm6000_register_extension); - -void tm6000_unregister_extension(struct tm6000_ops *ops) -{ - struct tm6000_core *dev = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_for_each_entry(dev, &tm6000_devlist, devlist) - ops->fini(dev); - - printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name); - list_del(&ops->next); - mutex_unlock(&tm6000_devlist_mutex); -} -EXPORT_SYMBOL(tm6000_unregister_extension); - -void tm6000_init_extension(struct tm6000_core *dev) -{ - struct tm6000_ops *ops = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->init) - ops->init(dev); - } - mutex_unlock(&tm6000_devlist_mutex); -} - -void tm6000_close_extension(struct tm6000_core *dev) -{ - struct tm6000_ops *ops = NULL; - - mutex_lock(&tm6000_devlist_mutex); - list_for_each_entry(ops, &tm6000_extension_devlist, next) { - if (ops->fini) - ops->fini(dev); - } - mutex_unlock(&tm6000_devlist_mutex); -} diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c b/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c deleted file mode 100644 index ee04973cbf93..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c +++ /dev/null @@ -1,454 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/usb.h> - -#include "tm6000.h" -#include "tm6000-regs.h" - -#include "zl10353.h" - -#include <media/tuner.h> - -#include "xc2028.h" -#include "xc5000.h" - -MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug message"); - -static inline void print_err_status(struct tm6000_core *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(dev, 1, "URB status %d [%s].\n", - status, errmsg); - } else { - dprintk(dev, 1, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -static void tm6000_urb_received(struct urb *urb) -{ - int ret; - struct tm6000_core *dev = urb->context; - - switch (urb->status) { - case 0: - case -ETIMEDOUT: - break; - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - return; - default: - print_err_status(dev, 0, urb->status); - } - - if (urb->actual_length > 0) - dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, - urb->actual_length); - - if (dev->dvb->streams > 0) { - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret < 0) { - printk(KERN_ERR "tm6000: error %s\n", __func__); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - dev->dvb->bulk_urb = NULL; - } - } -} - -static int tm6000_start_stream(struct tm6000_core *dev) -{ - int ret; - unsigned int pipe, size; - struct tm6000_dvb *dvb = dev->dvb; - - printk(KERN_INFO "tm6000: got start stream request %s\n", __func__); - - if (dev->mode != TM6000_MODE_DIGITAL) { - tm6000_init_digital_mode(dev); - dev->mode = TM6000_MODE_DIGITAL; - } - - dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dvb->bulk_urb) - return -ENOMEM; - - pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe); - size = size * 15; /* 512 x 8 or 12 or 15 */ - - dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); - if (!dvb->bulk_urb->transfer_buffer) { - usb_free_urb(dvb->bulk_urb); - dvb->bulk_urb = NULL; - return -ENOMEM; - } - - usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe, - dvb->bulk_urb->transfer_buffer, - size, - tm6000_urb_received, dev); - - ret = usb_clear_halt(dev->udev, pipe); - if (ret < 0) { - printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n", - ret, __func__); - - kfree(dvb->bulk_urb->transfer_buffer); - usb_free_urb(dvb->bulk_urb); - dvb->bulk_urb = NULL; - return ret; - } else - printk(KERN_ERR "tm6000: pipe reset\n"); - -/* mutex_lock(&tm6000_driver.open_close_mutex); */ - ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC); - -/* mutex_unlock(&tm6000_driver.open_close_mutex); */ - if (ret) { - printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n", - ret); - - kfree(dvb->bulk_urb->transfer_buffer); - usb_free_urb(dvb->bulk_urb); - dvb->bulk_urb = NULL; - return ret; - } - - return 0; -} - -static void tm6000_stop_stream(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dvb->bulk_urb) { - printk(KERN_INFO "urb killing\n"); - usb_kill_urb(dvb->bulk_urb); - printk(KERN_INFO "urb buffer free\n"); - kfree(dvb->bulk_urb->transfer_buffer); - usb_free_urb(dvb->bulk_urb); - dvb->bulk_urb = NULL; - } -} - -static int tm6000_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct tm6000_core *dev = demux->priv; - struct tm6000_dvb *dvb = dev->dvb; - printk(KERN_INFO "tm6000: got start feed request %s\n", __func__); - - mutex_lock(&dvb->mutex); - if (dvb->streams == 0) { - dvb->streams = 1; -/* mutex_init(&tm6000_dev->streming_mutex); */ - tm6000_start_stream(dev); - } else - ++(dvb->streams); - mutex_unlock(&dvb->mutex); - - return 0; -} - -static int tm6000_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct tm6000_core *dev = demux->priv; - struct tm6000_dvb *dvb = dev->dvb; - - printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__); - - mutex_lock(&dvb->mutex); - - printk(KERN_INFO "stream %#x\n", dvb->streams); - --(dvb->streams); - if (dvb->streams == 0) { - printk(KERN_INFO "stop stream\n"); - tm6000_stop_stream(dev); -/* mutex_destroy(&tm6000_dev->streaming_mutex); */ - } - mutex_unlock(&dvb->mutex); -/* mutex_destroy(&tm6000_dev->streaming_mutex); */ - - return 0; -} - -static int tm6000_dvb_attach_frontend(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dev->caps.has_zl10353) { - struct zl10353_config config = { - .demod_address = dev->demod_addr, - .no_tuner = 1, - .parallel_ts = 1, - .if2 = 45700, - .disable_i2c_gate_ctrl = 1, - }; - - dvb->frontend = dvb_attach(zl10353_attach, &config, - &dev->i2c_adap); - } else { - printk(KERN_ERR "tm6000: no frontend defined for the device!\n"); - return -1; - } - - return (!dvb->frontend) ? -1 : 0; -} - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int register_dvb(struct tm6000_core *dev) -{ - int ret = -1; - struct tm6000_dvb *dvb = dev->dvb; - - mutex_init(&dvb->mutex); - - dvb->streams = 0; - - /* attach the frontend */ - ret = tm6000_dvb_attach_frontend(dev); - if (ret < 0) { - printk(KERN_ERR "tm6000: couldn't attach the frontend!\n"); - goto err; - } - - ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", - THIS_MODULE, &dev->udev->dev, adapter_nr); - if (ret < 0) { - pr_err("tm6000: couldn't register the adapter!\n"); - goto err; - } - - dvb->adapter.priv = dev; - - if (dvb->frontend) { - switch (dev->tuner_type) { - case TUNER_XC2028: { - struct xc2028_config cfg = { - .i2c_adap = &dev->i2c_adap, - .i2c_addr = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_tuner_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; - } - - if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register frontend (xc3028)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC2028/3028 asked to be attached to frontend!\n"); - break; - } - case TUNER_XC5000: { - struct xc5000_config cfg = { - .i2c_address = dev->tuner_addr, - }; - - dvb->frontend->callback = tm6000_xc5000_callback; - ret = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (ret < 0) { - printk(KERN_ERR - "tm6000: couldn't register frontend\n"); - goto adapter_err; - } - - if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register frontend (xc5000)\n"); - ret = -EINVAL; - goto frontend_err; - } - printk(KERN_INFO "tm6000: XC5000 asked to be attached to frontend!\n"); - break; - } - } - } else - printk(KERN_ERR "tm6000: no frontend found\n"); - - dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING - | DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dev; - dvb->demux.filternum = 8; - dvb->demux.feednum = 8; - dvb->demux.start_feed = tm6000_start_feed; - dvb->demux.stop_feed = tm6000_stop_feed; - dvb->demux.write_to_decoder = NULL; - ret = dvb_dmx_init(&dvb->demux); - if (ret < 0) { - printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret); - goto frontend_err; - } - - dvb->dmxdev.filternum = dev->dvb->demux.filternum; - dvb->dmxdev.demux = &dev->dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (ret < 0) { - printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret); - goto dvb_dmx_err; - } - - return 0; - -dvb_dmx_err: - dvb_dmx_release(&dvb->demux); -frontend_err: - if (dvb->frontend) { - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - } -adapter_err: - dvb_unregister_adapter(&dvb->adapter); -err: - return ret; -} - -static void unregister_dvb(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb = dev->dvb; - - if (dvb->bulk_urb) { - struct urb *bulk_urb = dvb->bulk_urb; - - kfree(bulk_urb->transfer_buffer); - bulk_urb->transfer_buffer = NULL; - usb_unlink_urb(bulk_urb); - usb_free_urb(bulk_urb); - } - -/* mutex_lock(&tm6000_driver.open_close_mutex); */ - if (dvb->frontend) { - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - } - - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_adapter(&dvb->adapter); - mutex_destroy(&dvb->mutex); -/* mutex_unlock(&tm6000_driver.open_close_mutex); */ -} - -static int dvb_init(struct tm6000_core *dev) -{ - struct tm6000_dvb *dvb; - int rc; - - if (!dev) - return 0; - - if (!dev->caps.has_dvb) - return 0; - - if (dev->udev->speed == USB_SPEED_FULL) { - printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n"); - return 0; - } - - dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL); - if (!dvb) - return -ENOMEM; - - dev->dvb = dvb; - - rc = register_dvb(dev); - if (rc < 0) { - kfree(dvb); - dev->dvb = NULL; - return 0; - } - - return 0; -} - -static int dvb_fini(struct tm6000_core *dev) -{ - if (!dev) - return 0; - - if (!dev->caps.has_dvb) - return 0; - - if (dev->dvb) { - unregister_dvb(dev); - kfree(dev->dvb); - dev->dvb = NULL; - } - - return 0; -} - -static struct tm6000_ops dvb_ops = { - .type = TM6000_DVB, - .name = "TM6000 dvb Extension", - .init = dvb_init, - .fini = dvb_fini, -}; - -static int __init tm6000_dvb_register(void) -{ - return tm6000_register_extension(&dvb_ops); -} - -static void __exit tm6000_dvb_unregister(void) -{ - tm6000_unregister_extension(&dvb_ops); -} - -module_init(tm6000_dvb_register); -module_exit(tm6000_dvb_unregister); diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c b/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c deleted file mode 100644 index 7554b93b82e6..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c +++ /dev/null @@ -1,317 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// tm6000-i2c.c - driver for TM5600/TM6000/TM6010 USB video capture devices -// -// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> -// -// Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com> -// - Fix SMBus Read Byte command - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/usb.h> -#include <linux/i2c.h> - -#include "tm6000.h" -#include "tm6000-regs.h" -#include <media/v4l2-common.h> -#include <media/tuner.h> -#include "xc2028.h" - - -/* ----------------------------------------------------------- */ - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -#define i2c_dprintk(lvl, fmt, args...) if (i2c_debug >= lvl) do { \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __func__, ##args); } while (0) - -static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, - __u8 reg, char *buf, int len) -{ - int rc; - unsigned int i2c_packet_limit = 16; - - if (dev->dev_type == TM6010) - i2c_packet_limit = 80; - - if (!buf) - return -1; - - if (len < 1 || len > i2c_packet_limit) { - printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", - len, i2c_packet_limit); - return -1; - } - - /* capture mutex */ - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, - addr | reg << 8, 0, buf, len); - - if (rc < 0) { - /* release mutex */ - return rc; - } - - /* release mutex */ - return rc; -} - -/* Generic read - doesn't work fine with 16bit registers */ -static int tm6000_i2c_recv_regs(struct tm6000_core *dev, unsigned char addr, - __u8 reg, char *buf, int len) -{ - int rc; - u8 b[2]; - unsigned int i2c_packet_limit = 16; - - if (dev->dev_type == TM6010) - i2c_packet_limit = 64; - - if (!buf) - return -1; - - if (len < 1 || len > i2c_packet_limit) { - printk(KERN_ERR "Incorrect length of i2c packet = %d, limit set to %d\n", - len, i2c_packet_limit); - return -1; - } - - /* capture mutex */ - if ((dev->caps.has_zl10353) && (dev->demod_addr << 1 == addr) && (reg % 2 == 0)) { - /* - * Workaround an I2C bug when reading from zl10353 - */ - reg -= 1; - len += 1; - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, b, len); - - *buf = b[1]; - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_16_SET_GET_I2C_WR1_RDN, addr | reg << 8, 0, buf, len); - } - - /* release mutex */ - return rc; -} - -/* - * read from a 16bit register - * for example xc2028, xc3028 or xc3028L - */ -static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr, - __u16 reg, char *buf, int len) -{ - int rc; - unsigned char ureg; - - if (!buf || len != 2) - return -1; - - /* capture mutex */ - if (dev->dev_type == TM6010) { - ureg = reg & 0xFF; - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_16_SET_GET_I2C_WR1_RDN, - addr | (reg & 0xFF00), 0, &ureg, 1); - - if (rc < 0) { - /* release mutex */ - return rc; - } - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ, - reg, 0, buf, len); - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_14_SET_GET_I2C_WR2_RDN, - addr, reg, buf, len); - } - - /* release mutex */ - return rc; -} - -static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct tm6000_core *dev = i2c_adap->algo_data; - int addr, rc, i, byte; - - for (i = 0; i < num; i++) { - addr = (msgs[i].addr << 1) & 0xff; - i2c_dprintk(2, "%s %s addr=0x%x len=%d:", - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (msgs[i].flags & I2C_M_RD) { - /* read request without preceding register selection */ - /* - * The TM6000 only supports a read transaction - * immediately after a 1 or 2 byte write to select - * a register. We cannot fulfill this request. - */ - i2c_dprintk(2, " read without preceding write not supported"); - rc = -EOPNOTSUPP; - goto err; - } else if (i + 1 < num && msgs[i].len <= 2 && - (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* 1 or 2 byte write followed by a read */ - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(KERN_CONT " %02x", msgs[i].buf[byte]); - i2c_dprintk(2, "; joined to read %s len=%d:", - i == num - 2 ? "stop" : "nonstop", - msgs[i + 1].len); - - if (msgs[i].len == 2) { - rc = tm6000_i2c_recv_regs16(dev, addr, - msgs[i].buf[0] << 8 | msgs[i].buf[1], - msgs[i + 1].buf, msgs[i + 1].len); - } else { - rc = tm6000_i2c_recv_regs(dev, addr, msgs[i].buf[0], - msgs[i + 1].buf, msgs[i + 1].len); - } - - i++; - - if (addr == dev->tuner_addr << 1) { - tm6000_set_reg(dev, REQ_50_SET_START, 0, 0); - tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0); - } - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(KERN_CONT " %02x", msgs[i].buf[byte]); - } else { - /* write bytes */ - if (i2c_debug >= 2) - for (byte = 0; byte < msgs[i].len; byte++) - printk(KERN_CONT " %02x", msgs[i].buf[byte]); - rc = tm6000_i2c_send_regs(dev, addr, msgs[i].buf[0], - msgs[i].buf + 1, msgs[i].len - 1); - } - if (i2c_debug >= 2) - printk(KERN_CONT "\n"); - if (rc < 0) - goto err; - } - - return num; -err: - i2c_dprintk(2, " ERROR: %i\n", rc); - return rc; -} - -static int tm6000_i2c_eeprom(struct tm6000_core *dev) -{ - int i, rc; - unsigned char *p = dev->eedata; - unsigned char bytes[17]; - - dev->i2c_client.addr = 0xa0 >> 1; - dev->eedata_size = 0; - - bytes[16] = '\0'; - for (i = 0; i < sizeof(dev->eedata); ) { - *p = i; - rc = tm6000_i2c_recv_regs(dev, 0xa0, i, p, 1); - if (rc < 1) { - if (p == dev->eedata) - goto noeeprom; - else { - printk(KERN_WARNING - "%s: i2c eeprom read error (err=%d)\n", - dev->name, rc); - } - return -EINVAL; - } - dev->eedata_size++; - p++; - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); - printk(KERN_CONT " %02x", dev->eedata[i]); - if ((dev->eedata[i] >= ' ') && (dev->eedata[i] <= 'z')) - bytes[i%16] = dev->eedata[i]; - else - bytes[i%16] = '.'; - - i++; - - if (0 == (i % 16)) { - bytes[16] = '\0'; - printk(KERN_CONT " %s\n", bytes); - } - } - if (0 != (i%16)) { - bytes[i%16] = '\0'; - for (i %= 16; i < 16; i++) - printk(KERN_CONT " "); - printk(KERN_CONT " %s\n", bytes); - } - - return 0; - -noeeprom: - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", - dev->name, rc); - return -EINVAL; -} - -/* ----------------------------------------------------------- */ - -/* - * functionality() - */ -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm tm6000_algo = { - .master_xfer = tm6000_i2c_xfer, - .functionality = functionality, -}; - -/* ----------------------------------------------------------- */ - -/* - * tm6000_i2c_register() - * register i2c bus - */ -int tm6000_i2c_register(struct tm6000_core *dev) -{ - int rc; - - dev->i2c_adap.owner = THIS_MODULE; - dev->i2c_adap.algo = &tm6000_algo; - dev->i2c_adap.dev.parent = &dev->udev->dev; - strscpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name)); - dev->i2c_adap.algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - rc = i2c_add_adapter(&dev->i2c_adap); - if (rc) - return rc; - - dev->i2c_client.adapter = &dev->i2c_adap; - strscpy(dev->i2c_client.name, "tm6000 internal", I2C_NAME_SIZE); - tm6000_i2c_eeprom(dev); - - return 0; -} - -/* - * tm6000_i2c_unregister() - * unregister i2c_bus - */ -int tm6000_i2c_unregister(struct tm6000_core *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-input.c b/drivers/staging/media/deprecated/tm6000/tm6000-input.c deleted file mode 100644 index 5136e9e202f1..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-input.c +++ /dev/null @@ -1,503 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * tm6000-input.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (C) 2010 Stefan Ringel <stefan.ringel@arcor.de> - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/delay.h> - -#include <linux/input.h> -#include <linux/usb.h> - -#include <media/rc-core.h> - -#include "tm6000.h" -#include "tm6000-regs.h" - -static unsigned int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "debug message level"); - -static unsigned int enable_ir = 1; -module_param(enable_ir, int, 0644); -MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)"); - -static unsigned int ir_clock_mhz = 12; -module_param(ir_clock_mhz, int, 0644); -MODULE_PARM_DESC(ir_clock_mhz, "ir clock, in MHz"); - -#define URB_SUBMIT_DELAY 100 /* ms - Delay to submit an URB request on retrial and init */ -#define URB_INT_LED_DELAY 100 /* ms - Delay to turn led on again on int mode */ - -#undef dprintk - -#define dprintk(level, fmt, arg...) do {\ - if (ir_debug >= level) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } while (0) - -struct tm6000_ir_poll_result { - u16 rc_data; -}; - -struct tm6000_IR { - struct tm6000_core *dev; - struct rc_dev *rc; - char name[32]; - char phys[32]; - - /* poll expernal decoder */ - int polling; - struct delayed_work work; - u8 wait:1; - u8 pwled:2; - u8 submit_urb:1; - struct urb *int_urb; - - /* IR device properties */ - u64 rc_proto; -}; - -void tm6000_ir_wait(struct tm6000_core *dev, u8 state) -{ - struct tm6000_IR *ir = dev->ir; - - if (!dev->ir) - return; - - dprintk(2, "%s: %i\n",__func__, ir->wait); - - if (state) - ir->wait = 1; - else - ir->wait = 0; -} - -static int tm6000_ir_config(struct tm6000_IR *ir) -{ - struct tm6000_core *dev = ir->dev; - u32 pulse = 0, leader = 0; - - dprintk(2, "%s\n",__func__); - - /* - * The IR decoder supports RC-5 or NEC, with a configurable timing. - * The timing configuration there is not that accurate, as it uses - * approximate values. The NEC spec mentions a 562.5 unit period, - * and RC-5 uses a 888.8 period. - * Currently, driver assumes a clock provided by a 12 MHz XTAL, but - * a modprobe parameter can adjust it. - * Adjustments are required for other timings. - * It seems that the 900ms timing for NEC is used to detect a RC-5 - * IR, in order to discard such decoding - */ - - switch (ir->rc_proto) { - case RC_PROTO_BIT_NEC: - leader = 900; /* ms */ - pulse = 700; /* ms - the actual value would be 562 */ - break; - default: - case RC_PROTO_BIT_RC5: - leader = 900; /* ms - from the NEC decoding */ - pulse = 1780; /* ms - The actual value would be 1776 */ - break; - } - - pulse = ir_clock_mhz * pulse; - leader = ir_clock_mhz * leader; - if (ir->rc_proto == RC_PROTO_BIT_NEC) - leader = leader | 0x8000; - - dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n", - __func__, - (ir->rc_proto == RC_PROTO_BIT_NEC) ? "NEC" : "RC-5", - ir_clock_mhz, leader, pulse); - - /* Remote WAKEUP = enable, normal mode, from IR decoder output */ - tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); - - /* Enable IR reception on non-busrt mode */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR, 0x2f); - - /* IR_WKUP_SEL = Low byte in decoded IR data */ - tm6000_set_reg(dev, TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff); - /* IR_WKU_ADD code */ - tm6000_set_reg(dev, TM6010_REQ07_RDB_IR_WAKEUP_ADD, 0xff); - - tm6000_set_reg(dev, TM6010_REQ07_RDC_IR_LEADER1, leader >> 8); - tm6000_set_reg(dev, TM6010_REQ07_RDD_IR_LEADER0, leader); - - tm6000_set_reg(dev, TM6010_REQ07_RDE_IR_PULSE_CNT1, pulse >> 8); - tm6000_set_reg(dev, TM6010_REQ07_RDF_IR_PULSE_CNT0, pulse); - - if (!ir->polling) - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - else - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); - msleep(10); - - /* Shows that IR is working via the LED */ - tm6000_flash_led(dev, 0); - msleep(100); - tm6000_flash_led(dev, 1); - ir->pwled = 1; - - return 0; -} - -static void tm6000_ir_keydown(struct tm6000_IR *ir, - const char *buf, unsigned int len) -{ - u8 device, command; - u32 scancode; - enum rc_proto protocol; - - if (len < 1) - return; - - command = buf[0]; - device = (len > 1 ? buf[1] : 0x0); - switch (ir->rc_proto) { - case RC_PROTO_BIT_RC5: - protocol = RC_PROTO_RC5; - scancode = RC_SCANCODE_RC5(device, command); - break; - case RC_PROTO_BIT_NEC: - protocol = RC_PROTO_NEC; - scancode = RC_SCANCODE_NEC(device, command); - break; - default: - protocol = RC_PROTO_OTHER; - scancode = RC_SCANCODE_OTHER(device << 8 | command); - break; - } - - dprintk(1, "%s, protocol: 0x%04x, scancode: 0x%08x\n", - __func__, protocol, scancode); - rc_keydown(ir->rc, protocol, scancode, 0); -} - -static void tm6000_ir_urb_received(struct urb *urb) -{ - struct tm6000_core *dev = urb->context; - struct tm6000_IR *ir = dev->ir; - char *buf; - - dprintk(2, "%s\n",__func__); - if (urb->status < 0 || urb->actual_length <= 0) { - printk(KERN_INFO "tm6000: IR URB failure: status: %i, length %i\n", - urb->status, urb->actual_length); - ir->submit_urb = 1; - schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); - return; - } - buf = urb->transfer_buffer; - - if (ir_debug) - print_hex_dump(KERN_DEBUG, "tm6000: IR data: ", - DUMP_PREFIX_OFFSET,16, 1, - buf, urb->actual_length, false); - - tm6000_ir_keydown(ir, urb->transfer_buffer, urb->actual_length); - - usb_submit_urb(urb, GFP_ATOMIC); - /* - * Flash the led. We can't do it here, as it is running on IRQ context. - * So, use the scheduler to do it, in a few ms. - */ - ir->pwled = 2; - schedule_delayed_work(&ir->work, msecs_to_jiffies(10)); -} - -static void tm6000_ir_handle_key(struct work_struct *work) -{ - struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); - struct tm6000_core *dev = ir->dev; - int rc; - u8 buf[2]; - - if (ir->wait) - return; - - dprintk(3, "%s\n",__func__); - - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 2); - if (rc < 0) - return; - - /* Check if something was read */ - if ((buf[0] & 0xff) == 0xff) { - if (!ir->pwled) { - tm6000_flash_led(dev, 1); - ir->pwled = 1; - } - return; - } - - tm6000_ir_keydown(ir, buf, rc); - tm6000_flash_led(dev, 0); - ir->pwled = 0; - - /* Re-schedule polling */ - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); -} - -static void tm6000_ir_int_work(struct work_struct *work) -{ - struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); - struct tm6000_core *dev = ir->dev; - int rc; - - dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb, - ir->pwled); - - if (ir->submit_urb) { - dprintk(3, "Resubmit urb\n"); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - - rc = usb_submit_urb(ir->int_urb, GFP_ATOMIC); - if (rc < 0) { - printk(KERN_ERR "tm6000: Can't submit an IR interrupt. Error %i\n", - rc); - /* Retry in 100 ms */ - schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); - return; - } - ir->submit_urb = 0; - } - - /* Led is enabled only if USB submit doesn't fail */ - if (ir->pwled == 2) { - tm6000_flash_led(dev, 0); - ir->pwled = 0; - schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_INT_LED_DELAY)); - } else if (!ir->pwled) { - tm6000_flash_led(dev, 1); - ir->pwled = 1; - } -} - -static int tm6000_ir_start(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - - dprintk(2, "%s\n",__func__); - - schedule_delayed_work(&ir->work, 0); - - return 0; -} - -static void tm6000_ir_stop(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - - dprintk(2, "%s\n",__func__); - - cancel_delayed_work_sync(&ir->work); -} - -static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) -{ - struct tm6000_IR *ir = rc->priv; - - if (!ir) - return 0; - - dprintk(2, "%s\n",__func__); - - ir->rc_proto = *rc_proto; - - tm6000_ir_config(ir); - /* TODO */ - return 0; -} - -static int __tm6000_ir_int_start(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - struct tm6000_core *dev; - int pipe, size; - int err = -ENOMEM; - - if (!ir) - return -ENODEV; - dev = ir->dev; - - dprintk(2, "%s\n",__func__); - - ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!ir->int_urb) - return -ENOMEM; - - pipe = usb_rcvintpipe(dev->udev, - dev->int_in.endp->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe); - dprintk(1, "IR max size: %d\n", size); - - ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC); - if (!ir->int_urb->transfer_buffer) { - usb_free_urb(ir->int_urb); - return err; - } - dprintk(1, "int interval: %d\n", dev->int_in.endp->desc.bInterval); - - usb_fill_int_urb(ir->int_urb, dev->udev, pipe, - ir->int_urb->transfer_buffer, size, - tm6000_ir_urb_received, dev, - dev->int_in.endp->desc.bInterval); - - ir->submit_urb = 1; - schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); - - return 0; -} - -static void __tm6000_ir_int_stop(struct rc_dev *rc) -{ - struct tm6000_IR *ir = rc->priv; - - if (!ir || !ir->int_urb) - return; - - dprintk(2, "%s\n",__func__); - - usb_kill_urb(ir->int_urb); - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - ir->int_urb = NULL; -} - -int tm6000_ir_int_start(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - - if (!ir) - return 0; - - return __tm6000_ir_int_start(ir->rc); -} - -void tm6000_ir_int_stop(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - - if (!ir || !ir->rc) - return; - - __tm6000_ir_int_stop(ir->rc); -} - -int tm6000_ir_init(struct tm6000_core *dev) -{ - struct tm6000_IR *ir; - struct rc_dev *rc; - int err = -ENOMEM; - u64 rc_proto; - - if (!enable_ir) - return -ENODEV; - - if (!dev->caps.has_remote) - return 0; - - if (!dev->ir_codes) - return 0; - - ir = kzalloc(sizeof(*ir), GFP_ATOMIC); - rc = rc_allocate_device(RC_DRIVER_SCANCODE); - if (!ir || !rc) - goto out; - - dprintk(2, "%s\n", __func__); - - /* record handles to ourself */ - ir->dev = dev; - dev->ir = ir; - ir->rc = rc; - - /* input setup */ - rc->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_NEC; - /* Needed, in order to support NEC remotes with 24 or 32 bits */ - rc->scancode_mask = 0xffff; - rc->priv = ir; - rc->change_protocol = tm6000_ir_change_protocol; - if (dev->int_in.endp) { - rc->open = __tm6000_ir_int_start; - rc->close = __tm6000_ir_int_stop; - INIT_DELAYED_WORK(&ir->work, tm6000_ir_int_work); - } else { - rc->open = tm6000_ir_start; - rc->close = tm6000_ir_stop; - ir->polling = 50; - INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key); - } - - snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", - dev->name); - - usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); - strlcat(ir->phys, "/input0", sizeof(ir->phys)); - - rc_proto = RC_PROTO_BIT_UNKNOWN; - tm6000_ir_change_protocol(rc, &rc_proto); - - rc->device_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_USB; - rc->input_id.version = 1; - rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); - rc->map_name = dev->ir_codes; - rc->driver_name = "tm6000"; - rc->dev.parent = &dev->udev->dev; - - /* ir register */ - err = rc_register_device(rc); - if (err) - goto out; - - return 0; - -out: - dev->ir = NULL; - rc_free_device(rc); - kfree(ir); - return err; -} - -int tm6000_ir_fini(struct tm6000_core *dev) -{ - struct tm6000_IR *ir = dev->ir; - - /* skip detach on non attached board */ - - if (!ir) - return 0; - - dprintk(2, "%s\n",__func__); - - if (!ir->polling) - __tm6000_ir_int_stop(ir->rc); - - tm6000_ir_stop(ir->rc); - - /* Turn off the led */ - tm6000_flash_led(dev, 0); - ir->pwled = 0; - - rc_unregister_device(ir->rc); - - kfree(ir); - dev->ir = NULL; - - return 0; -} diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-regs.h b/drivers/staging/media/deprecated/tm6000/tm6000-regs.h deleted file mode 100644 index 6a181f2e7ef2..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-regs.h +++ /dev/null @@ -1,588 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> - */ - -/* - * Define TV Master TM5600/TM6000/TM6010 Request codes - */ -#define REQ_00_SET_IR_VALUE 0 -#define REQ_01_SET_WAKEUP_IRCODE 1 -#define REQ_02_GET_IR_CODE 2 -#define REQ_03_SET_GET_MCU_PIN 3 -#define REQ_04_EN_DISABLE_MCU_INT 4 -#define REQ_05_SET_GET_USBREG 5 - /* Write: RegNum, Value, 0 */ - /* Read : RegNum, Value, 1, RegStatus */ -#define REQ_06_SET_GET_USBREG_BIT 6 -#define REQ_07_SET_GET_AVREG 7 - /* Write: RegNum, Value, 0 */ - /* Read : RegNum, Value, 1, RegStatus */ -#define REQ_08_SET_GET_AVREG_BIT 8 -#define REQ_09_SET_GET_TUNER_FQ 9 -#define REQ_10_SET_TUNER_SYSTEM 10 -#define REQ_11_SET_EEPROM_ADDR 11 -#define REQ_12_SET_GET_EEPROMBYTE 12 -#define REQ_13_GET_EEPROM_SEQREAD 13 -#define REQ_14_SET_GET_I2C_WR2_RDN 14 -#define REQ_15_SET_GET_I2CBYTE 15 - /* Write: Subaddr, Slave Addr, value, 0 */ - /* Read : Subaddr, Slave Addr, value, 1 */ -#define REQ_16_SET_GET_I2C_WR1_RDN 16 - /* Subaddr, Slave Addr, 0, length */ -#define REQ_17_SET_GET_I2CFP 17 - /* Write: Slave Addr, register, value */ - /* Read : Slave Addr, register, 2, data */ -#define REQ_20_DATA_TRANSFER 20 -#define REQ_30_I2C_WRITE 30 -#define REQ_31_I2C_READ 31 -#define REQ_35_AFTEK_TUNER_READ 35 -#define REQ_40_GET_VERSION 40 -#define REQ_50_SET_START 50 -#define REQ_51_SET_STOP 51 -#define REQ_52_TRANSMIT_DATA 52 -#define REQ_53_SPI_INITIAL 53 -#define REQ_54_SPI_SETSTART 54 -#define REQ_55_SPI_INOUTDATA 55 -#define REQ_56_SPI_SETSTOP 56 - -/* - * Define TV Master TM5600/TM6000/TM6010 GPIO lines - */ - -#define TM6000_GPIO_CLK 0x101 -#define TM6000_GPIO_DATA 0x100 - -#define TM6000_GPIO_1 0x102 -#define TM6000_GPIO_2 0x103 -#define TM6000_GPIO_3 0x104 -#define TM6000_GPIO_4 0x300 -#define TM6000_GPIO_5 0x301 -#define TM6000_GPIO_6 0x304 -#define TM6000_GPIO_7 0x305 - -/* tm6010 defines GPIO with different values */ -#define TM6010_GPIO_0 0x0102 -#define TM6010_GPIO_1 0x0103 -#define TM6010_GPIO_2 0x0104 -#define TM6010_GPIO_3 0x0105 -#define TM6010_GPIO_4 0x0106 -#define TM6010_GPIO_5 0x0107 -#define TM6010_GPIO_6 0x0300 -#define TM6010_GPIO_7 0x0301 -#define TM6010_GPIO_9 0x0305 -/* - * Define TV Master TM5600/TM6000/TM6010 URB message codes and length - */ - -enum { - TM6000_URB_MSG_VIDEO = 1, - TM6000_URB_MSG_AUDIO, - TM6000_URB_MSG_VBI, - TM6000_URB_MSG_PTS, - TM6000_URB_MSG_ERR, -}; - -/* Define specific TM6000 Video decoder registers */ -#define TM6000_REQ07_RD8_TEST_SEL 0x07, 0xd8 -#define TM6000_REQ07_RD9_A_SIM_SEL 0x07, 0xd9 -#define TM6000_REQ07_RDA_CLK_SEL 0x07, 0xda -#define TM6000_REQ07_RDB_OUT_SEL 0x07, 0xdb -#define TM6000_REQ07_RDC_NSEL_I2S 0x07, 0xdc -#define TM6000_REQ07_RDD_GPIO2_MDRV 0x07, 0xdd -#define TM6000_REQ07_RDE_GPIO1_MDRV 0x07, 0xde -#define TM6000_REQ07_RDF_PWDOWN_ACLK 0x07, 0xdf -#define TM6000_REQ07_RE0_VADC_REF_CTL 0x07, 0xe0 -#define TM6000_REQ07_RE1_VADC_DACLIMP 0x07, 0xe1 -#define TM6000_REQ07_RE2_VADC_STATUS_CTL 0x07, 0xe2 -#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1 0x07, 0xe3 -#define TM6000_REQ07_RE4_VADC_TARGET1 0x07, 0xe4 -#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2 0x07, 0xe5 -#define TM6000_REQ07_RE6_VADC_TARGET2 0x07, 0xe6 -#define TM6000_REQ07_RE7_VADC_AGAIN_CTL 0x07, 0xe7 -#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL 0x07, 0xe8 -#define TM6000_REQ07_RE9_VADC_INPUT_CTL1 0x07, 0xe9 -#define TM6000_REQ07_REA_VADC_INPUT_CTL2 0x07, 0xea -#define TM6000_REQ07_REB_VADC_AADC_MODE 0x07, 0xeb -#define TM6000_REQ07_REC_VADC_AADC_LVOL 0x07, 0xec -#define TM6000_REQ07_RED_VADC_AADC_RVOL 0x07, 0xed -#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL 0x07, 0xee -#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL 0x07, 0xef -#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW 0x07, 0xfd -#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH 0x07, 0xfe - -/* Define TM6000/TM6010 Video decoder registers */ -#define TM6010_REQ07_R00_VIDEO_CONTROL0 0x07, 0x00 -#define TM6010_REQ07_R01_VIDEO_CONTROL1 0x07, 0x01 -#define TM6010_REQ07_R02_VIDEO_CONTROL2 0x07, 0x02 -#define TM6010_REQ07_R03_YC_SEP_CONTROL 0x07, 0x03 -#define TM6010_REQ07_R04_LUMA_HAGC_CONTROL 0x07, 0x04 -#define TM6010_REQ07_R05_NOISE_THRESHOLD 0x07, 0x05 -#define TM6010_REQ07_R06_AGC_GATE_THRESHOLD 0x07, 0x06 -#define TM6010_REQ07_R07_OUTPUT_CONTROL 0x07, 0x07 -#define TM6010_REQ07_R08_LUMA_CONTRAST_ADJ 0x07, 0x08 -#define TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ 0x07, 0x09 -#define TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ 0x07, 0x0a -#define TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ 0x07, 0x0b -#define TM6010_REQ07_R0C_CHROMA_AGC_CONTROL 0x07, 0x0c -#define TM6010_REQ07_R0D_CHROMA_KILL_LEVEL 0x07, 0x0d -#define TM6010_REQ07_R0F_CHROMA_AUTO_POSITION 0x07, 0x0f -#define TM6010_REQ07_R10_AGC_PEAK_NOMINAL 0x07, 0x10 -#define TM6010_REQ07_R11_AGC_PEAK_CONTROL 0x07, 0x11 -#define TM6010_REQ07_R12_AGC_GATE_STARTH 0x07, 0x12 -#define TM6010_REQ07_R13_AGC_GATE_STARTL 0x07, 0x13 -#define TM6010_REQ07_R14_AGC_GATE_WIDTH 0x07, 0x14 -#define TM6010_REQ07_R15_AGC_BP_DELAY 0x07, 0x15 -#define TM6010_REQ07_R16_LOCK_COUNT 0x07, 0x16 -#define TM6010_REQ07_R17_HLOOP_MAXSTATE 0x07, 0x17 -#define TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3 0x07, 0x18 -#define TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2 0x07, 0x19 -#define TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1 0x07, 0x1a -#define TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0 0x07, 0x1b -#define TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3 0x07, 0x1c -#define TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2 0x07, 0x1d -#define TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1 0x07, 0x1e -#define TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0 0x07, 0x1f -#define TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME 0x07, 0x20 -#define TM6010_REQ07_R21_HSYNC_PHASE_OFFSET 0x07, 0x21 -#define TM6010_REQ07_R22_HSYNC_PLL_START_TIME 0x07, 0x22 -#define TM6010_REQ07_R23_HSYNC_PLL_END_TIME 0x07, 0x23 -#define TM6010_REQ07_R24_HSYNC_TIP_START_TIME 0x07, 0x24 -#define TM6010_REQ07_R25_HSYNC_TIP_END_TIME 0x07, 0x25 -#define TM6010_REQ07_R26_HSYNC_RISING_EDGE_START 0x07, 0x26 -#define TM6010_REQ07_R27_HSYNC_RISING_EDGE_END 0x07, 0x27 -#define TM6010_REQ07_R28_BACKPORCH_START 0x07, 0x28 -#define TM6010_REQ07_R29_BACKPORCH_END 0x07, 0x29 -#define TM6010_REQ07_R2A_HSYNC_FILTER_START 0x07, 0x2a -#define TM6010_REQ07_R2B_HSYNC_FILTER_END 0x07, 0x2b -#define TM6010_REQ07_R2C_CHROMA_BURST_START 0x07, 0x2c -#define TM6010_REQ07_R2D_CHROMA_BURST_END 0x07, 0x2d -#define TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART 0x07, 0x2e -#define TM6010_REQ07_R2F_ACTIVE_VIDEO_HWIDTH 0x07, 0x2f -#define TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART 0x07, 0x30 -#define TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT 0x07, 0x31 -#define TM6010_REQ07_R32_VSYNC_HLOCK_MIN 0x07, 0x32 -#define TM6010_REQ07_R33_VSYNC_HLOCK_MAX 0x07, 0x33 -#define TM6010_REQ07_R34_VSYNC_AGC_MIN 0x07, 0x34 -#define TM6010_REQ07_R35_VSYNC_AGC_MAX 0x07, 0x35 -#define TM6010_REQ07_R36_VSYNC_VBI_MIN 0x07, 0x36 -#define TM6010_REQ07_R37_VSYNC_VBI_MAX 0x07, 0x37 -#define TM6010_REQ07_R38_VSYNC_THRESHOLD 0x07, 0x38 -#define TM6010_REQ07_R39_VSYNC_TIME_CONSTANT 0x07, 0x39 -#define TM6010_REQ07_R3A_STATUS1 0x07, 0x3a -#define TM6010_REQ07_R3B_STATUS2 0x07, 0x3b -#define TM6010_REQ07_R3C_STATUS3 0x07, 0x3c -#define TM6010_REQ07_R3F_RESET 0x07, 0x3f -#define TM6010_REQ07_R40_TELETEXT_VBI_CODE0 0x07, 0x40 -#define TM6010_REQ07_R41_TELETEXT_VBI_CODE1 0x07, 0x41 -#define TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL 0x07, 0x42 -#define TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7 0x07, 0x43 -#define TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8 0x07, 0x44 -#define TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9 0x07, 0x45 -#define TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10 0x07, 0x46 -#define TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11 0x07, 0x47 -#define TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12 0x07, 0x48 -#define TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13 0x07, 0x49 -#define TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14 0x07, 0x4a -#define TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15 0x07, 0x4b -#define TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16 0x07, 0x4c -#define TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17 0x07, 0x4d -#define TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18 0x07, 0x4e -#define TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19 0x07, 0x4f -#define TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20 0x07, 0x50 -#define TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21 0x07, 0x51 -#define TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22 0x07, 0x52 -#define TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23 0x07, 0x53 -#define TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES 0x07, 0x54 -#define TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN 0x07, 0x55 -#define TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN 0x07, 0x56 -#define TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN 0x07, 0x57 -#define TM6010_REQ07_R58_VBI_CAPTION_DTO1 0x07, 0x58 -#define TM6010_REQ07_R59_VBI_CAPTION_DTO0 0x07, 0x59 -#define TM6010_REQ07_R5A_VBI_TELETEXT_DTO1 0x07, 0x5a -#define TM6010_REQ07_R5B_VBI_TELETEXT_DTO0 0x07, 0x5b -#define TM6010_REQ07_R5C_VBI_WSS625_DTO1 0x07, 0x5c -#define TM6010_REQ07_R5D_VBI_WSS625_DTO0 0x07, 0x5d -#define TM6010_REQ07_R5E_VBI_CAPTION_FRAME_START 0x07, 0x5e -#define TM6010_REQ07_R5F_VBI_WSS625_FRAME_START 0x07, 0x5f -#define TM6010_REQ07_R60_TELETEXT_FRAME_START 0x07, 0x60 -#define TM6010_REQ07_R61_VBI_CCDATA1 0x07, 0x61 -#define TM6010_REQ07_R62_VBI_CCDATA2 0x07, 0x62 -#define TM6010_REQ07_R63_VBI_WSS625_DATA1 0x07, 0x63 -#define TM6010_REQ07_R64_VBI_WSS625_DATA2 0x07, 0x64 -#define TM6010_REQ07_R65_VBI_DATA_STATUS 0x07, 0x65 -#define TM6010_REQ07_R66_VBI_CAPTION_START 0x07, 0x66 -#define TM6010_REQ07_R67_VBI_WSS625_START 0x07, 0x67 -#define TM6010_REQ07_R68_VBI_TELETEXT_START 0x07, 0x68 -#define TM6010_REQ07_R70_HSYNC_DTO_INC_STATUS3 0x07, 0x70 -#define TM6010_REQ07_R71_HSYNC_DTO_INC_STATUS2 0x07, 0x71 -#define TM6010_REQ07_R72_HSYNC_DTO_INC_STATUS1 0x07, 0x72 -#define TM6010_REQ07_R73_HSYNC_DTO_INC_STATUS0 0x07, 0x73 -#define TM6010_REQ07_R74_CHROMA_DTO_INC_STATUS3 0x07, 0x74 -#define TM6010_REQ07_R75_CHROMA_DTO_INC_STATUS2 0x07, 0x75 -#define TM6010_REQ07_R76_CHROMA_DTO_INC_STATUS1 0x07, 0x76 -#define TM6010_REQ07_R77_CHROMA_DTO_INC_STATUS0 0x07, 0x77 -#define TM6010_REQ07_R78_AGC_AGAIN_STATUS 0x07, 0x78 -#define TM6010_REQ07_R79_AGC_DGAIN_STATUS 0x07, 0x79 -#define TM6010_REQ07_R7A_CHROMA_MAG_STATUS 0x07, 0x7a -#define TM6010_REQ07_R7B_CHROMA_GAIN_STATUS1 0x07, 0x7b -#define TM6010_REQ07_R7C_CHROMA_GAIN_STATUS0 0x07, 0x7c -#define TM6010_REQ07_R7D_CORDIC_FREQ_STATUS 0x07, 0x7d -#define TM6010_REQ07_R7F_STATUS_NOISE 0x07, 0x7f -#define TM6010_REQ07_R80_COMB_FILTER_TRESHOLD 0x07, 0x80 -#define TM6010_REQ07_R82_COMB_FILTER_CONFIG 0x07, 0x82 -#define TM6010_REQ07_R83_CHROMA_LOCK_CONFIG 0x07, 0x83 -#define TM6010_REQ07_R84_NOISE_NTSC_C 0x07, 0x84 -#define TM6010_REQ07_R85_NOISE_PAL_C 0x07, 0x85 -#define TM6010_REQ07_R86_NOISE_PHASE_C 0x07, 0x86 -#define TM6010_REQ07_R87_NOISE_PHASE_Y 0x07, 0x87 -#define TM6010_REQ07_R8A_CHROMA_LOOPFILTER_STATE 0x07, 0x8a -#define TM6010_REQ07_R8B_CHROMA_HRESAMPLER 0x07, 0x8b -#define TM6010_REQ07_R8D_CPUMP_DELAY_ADJ 0x07, 0x8d -#define TM6010_REQ07_R8E_CPUMP_ADJ 0x07, 0x8e -#define TM6010_REQ07_R8F_CPUMP_DELAY 0x07, 0x8f - -/* Define TM6000/TM6010 Miscellaneous registers */ -#define TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE 0x07, 0xc0 -#define TM6010_REQ07_RC1_TRESHOLD 0x07, 0xc1 -#define TM6010_REQ07_RC2_HSYNC_WIDTH 0x07, 0xc2 -#define TM6010_REQ07_RC3_HSTART1 0x07, 0xc3 -#define TM6010_REQ07_RC4_HSTART0 0x07, 0xc4 -#define TM6010_REQ07_RC5_HEND1 0x07, 0xc5 -#define TM6010_REQ07_RC6_HEND0 0x07, 0xc6 -#define TM6010_REQ07_RC7_VSTART1 0x07, 0xc7 -#define TM6010_REQ07_RC8_VSTART0 0x07, 0xc8 -#define TM6010_REQ07_RC9_VEND1 0x07, 0xc9 -#define TM6010_REQ07_RCA_VEND0 0x07, 0xca -#define TM6010_REQ07_RCB_DELAY 0x07, 0xcb -/* ONLY for TM6010 */ -#define TM6010_REQ07_RCC_ACTIVE_IF 0x07, 0xcc -#define TM6010_REQ07_RCC_ACTIVE_IF_VIDEO_ENABLE (1 << 5) -#define TM6010_REQ07_RCC_ACTIVE_IF_AUDIO_ENABLE (1 << 6) -#define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0 -#define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1 -#define TM6010_REQ07_RD2_ADDR_FOR_REQ2 0x07, 0xd2 -#define TM6010_REQ07_RD3_ADDR_FOR_REQ3 0x07, 0xd3 -#define TM6010_REQ07_RD4_ADDR_FOR_REQ4 0x07, 0xd4 -#define TM6010_REQ07_RD5_POWERSAVE 0x07, 0xd5 -#define TM6010_REQ07_RD6_ENDP_REQ1_REQ2 0x07, 0xd6 -#define TM6010_REQ07_RD7_ENDP_REQ3_REQ4 0x07, 0xd7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR 0x07, 0xd8 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RD9_IR_BSIZE 0x07, 0xd9 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RDA_IR_WAKEUP_SEL 0x07, 0xda -/* ONLY for TM6010 */ -#define TM6010_REQ07_RDB_IR_WAKEUP_ADD 0x07, 0xdb -/* ONLY for TM6010 */ -#define TM6010_REQ07_RDC_IR_LEADER1 0x07, 0xdc -/* ONLY for TM6010 */ -#define TM6010_REQ07_RDD_IR_LEADER0 0x07, 0xdd -/* ONLY for TM6010 */ -#define TM6010_REQ07_RDE_IR_PULSE_CNT1 0x07, 0xde -/* ONLY for TM6010 */ -#define TM6010_REQ07_RDF_IR_PULSE_CNT0 0x07, 0xdf -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF 0x07, 0xe1 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE2_OUT_SEL2 0x07, 0xe2 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE3_OUT_SEL1 0x07, 0xe3 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE4_OUT_SEL0 0x07, 0xe4 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE5_REMOTE_WAKEUP 0x07, 0xe5 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE7_PUB_GPIO 0x07, 0xe7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE8_TYPESEL_MOS_I2S 0x07, 0xe8 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RE9_TYPESEL_MOS_TS 0x07, 0xe9 -/* ONLY for TM6010 */ -#define TM6010_REQ07_REA_TYPESEL_MOS_CCIR 0x07, 0xea -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF0_BIST_CRC_RESULT0 0x07, 0xf0 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF1_BIST_CRC_RESULT1 0x07, 0xf1 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF2_BIST_CRC_RESULT2 0x07, 0xf2 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF3_BIST_CRC_RESULT3 0x07, 0xf3 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF4_BIST_ERR_VST2 0x07, 0xf4 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF5_BIST_ERR_VST1 0x07, 0xf5 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF6_BIST_ERR_VST0 0x07, 0xf6 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RF7_BIST 0x07, 0xf7 -/* ONLY for TM6010 */ -#define TM6010_REQ07_RFE_POWER_DOWN 0x07, 0xfe -#define TM6010_REQ07_RFF_SOFT_RESET 0x07, 0xff - -/* Define TM6000/TM6010 USB registers */ -#define TM6010_REQ05_R00_MAIN_CTRL 0x05, 0x00 -#define TM6010_REQ05_R01_DEVADDR 0x05, 0x01 -#define TM6010_REQ05_R02_TEST 0x05, 0x02 -#define TM6010_REQ05_R04_SOFN0 0x05, 0x04 -#define TM6010_REQ05_R05_SOFN1 0x05, 0x05 -#define TM6010_REQ05_R06_SOFTM0 0x05, 0x06 -#define TM6010_REQ05_R07_SOFTM1 0x05, 0x07 -#define TM6010_REQ05_R08_PHY_TEST 0x05, 0x08 -#define TM6010_REQ05_R09_VCTL 0x05, 0x09 -#define TM6010_REQ05_R0A_VSTA 0x05, 0x0a -#define TM6010_REQ05_R0B_CX_CFG 0x05, 0x0b -#define TM6010_REQ05_R0C_ENDP0_REG0 0x05, 0x0c -#define TM6010_REQ05_R10_GMASK 0x05, 0x10 -#define TM6010_REQ05_R11_IMASK0 0x05, 0x11 -#define TM6010_REQ05_R12_IMASK1 0x05, 0x12 -#define TM6010_REQ05_R13_IMASK2 0x05, 0x13 -#define TM6010_REQ05_R14_IMASK3 0x05, 0x14 -#define TM6010_REQ05_R15_IMASK4 0x05, 0x15 -#define TM6010_REQ05_R16_IMASK5 0x05, 0x16 -#define TM6010_REQ05_R17_IMASK6 0x05, 0x17 -#define TM6010_REQ05_R18_IMASK7 0x05, 0x18 -#define TM6010_REQ05_R19_ZEROP0 0x05, 0x19 -#define TM6010_REQ05_R1A_ZEROP1 0x05, 0x1a -#define TM6010_REQ05_R1C_FIFO_EMP0 0x05, 0x1c -#define TM6010_REQ05_R1D_FIFO_EMP1 0x05, 0x1d -#define TM6010_REQ05_R20_IRQ_GROUP 0x05, 0x20 -#define TM6010_REQ05_R21_IRQ_SOURCE0 0x05, 0x21 -#define TM6010_REQ05_R22_IRQ_SOURCE1 0x05, 0x22 -#define TM6010_REQ05_R23_IRQ_SOURCE2 0x05, 0x23 -#define TM6010_REQ05_R24_IRQ_SOURCE3 0x05, 0x24 -#define TM6010_REQ05_R25_IRQ_SOURCE4 0x05, 0x25 -#define TM6010_REQ05_R26_IRQ_SOURCE5 0x05, 0x26 -#define TM6010_REQ05_R27_IRQ_SOURCE6 0x05, 0x27 -#define TM6010_REQ05_R28_IRQ_SOURCE7 0x05, 0x28 -#define TM6010_REQ05_R29_SEQ_ERR0 0x05, 0x29 -#define TM6010_REQ05_R2A_SEQ_ERR1 0x05, 0x2a -#define TM6010_REQ05_R2B_SEQ_ABORT0 0x05, 0x2b -#define TM6010_REQ05_R2C_SEQ_ABORT1 0x05, 0x2c -#define TM6010_REQ05_R2D_TX_ZERO0 0x05, 0x2d -#define TM6010_REQ05_R2E_TX_ZERO1 0x05, 0x2e -#define TM6010_REQ05_R2F_IDLE_CNT 0x05, 0x2f -#define TM6010_REQ05_R30_FNO_P1 0x05, 0x30 -#define TM6010_REQ05_R31_FNO_P2 0x05, 0x31 -#define TM6010_REQ05_R32_FNO_P3 0x05, 0x32 -#define TM6010_REQ05_R33_FNO_P4 0x05, 0x33 -#define TM6010_REQ05_R34_FNO_P5 0x05, 0x34 -#define TM6010_REQ05_R35_FNO_P6 0x05, 0x35 -#define TM6010_REQ05_R36_FNO_P7 0x05, 0x36 -#define TM6010_REQ05_R37_FNO_P8 0x05, 0x37 -#define TM6010_REQ05_R38_FNO_P9 0x05, 0x38 -#define TM6010_REQ05_R30_FNO_P10 0x05, 0x39 -#define TM6010_REQ05_R30_FNO_P11 0x05, 0x3a -#define TM6010_REQ05_R30_FNO_P12 0x05, 0x3b -#define TM6010_REQ05_R30_FNO_P13 0x05, 0x3c -#define TM6010_REQ05_R30_FNO_P14 0x05, 0x3d -#define TM6010_REQ05_R30_FNO_P15 0x05, 0x3e -#define TM6010_REQ05_R40_IN_MAXPS_LOW1 0x05, 0x40 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH1 0x05, 0x41 -#define TM6010_REQ05_R42_IN_MAXPS_LOW2 0x05, 0x42 -#define TM6010_REQ05_R43_IN_MAXPS_HIGH2 0x05, 0x43 -#define TM6010_REQ05_R44_IN_MAXPS_LOW3 0x05, 0x44 -#define TM6010_REQ05_R45_IN_MAXPS_HIGH3 0x05, 0x45 -#define TM6010_REQ05_R46_IN_MAXPS_LOW4 0x05, 0x46 -#define TM6010_REQ05_R47_IN_MAXPS_HIGH4 0x05, 0x47 -#define TM6010_REQ05_R48_IN_MAXPS_LOW5 0x05, 0x48 -#define TM6010_REQ05_R49_IN_MAXPS_HIGH5 0x05, 0x49 -#define TM6010_REQ05_R4A_IN_MAXPS_LOW6 0x05, 0x4a -#define TM6010_REQ05_R4B_IN_MAXPS_HIGH6 0x05, 0x4b -#define TM6010_REQ05_R4C_IN_MAXPS_LOW7 0x05, 0x4c -#define TM6010_REQ05_R4D_IN_MAXPS_HIGH7 0x05, 0x4d -#define TM6010_REQ05_R4E_IN_MAXPS_LOW8 0x05, 0x4e -#define TM6010_REQ05_R4F_IN_MAXPS_HIGH8 0x05, 0x4f -#define TM6010_REQ05_R50_IN_MAXPS_LOW9 0x05, 0x50 -#define TM6010_REQ05_R51_IN_MAXPS_HIGH9 0x05, 0x51 -#define TM6010_REQ05_R40_IN_MAXPS_LOW10 0x05, 0x52 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH10 0x05, 0x53 -#define TM6010_REQ05_R40_IN_MAXPS_LOW11 0x05, 0x54 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH11 0x05, 0x55 -#define TM6010_REQ05_R40_IN_MAXPS_LOW12 0x05, 0x56 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH12 0x05, 0x57 -#define TM6010_REQ05_R40_IN_MAXPS_LOW13 0x05, 0x58 -#define TM6010_REQ05_R41_IN_MAXPS_HIGH13 0x05, 0x59 -#define TM6010_REQ05_R40_IN_MAXPS_LOW14 0x05, 0x5a -#define TM6010_REQ05_R41_IN_MAXPS_HIGH14 0x05, 0x5b -#define TM6010_REQ05_R40_IN_MAXPS_LOW15 0x05, 0x5c -#define TM6010_REQ05_R41_IN_MAXPS_HIGH15 0x05, 0x5d -#define TM6010_REQ05_R60_OUT_MAXPS_LOW1 0x05, 0x60 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH1 0x05, 0x61 -#define TM6010_REQ05_R62_OUT_MAXPS_LOW2 0x05, 0x62 -#define TM6010_REQ05_R63_OUT_MAXPS_HIGH2 0x05, 0x63 -#define TM6010_REQ05_R64_OUT_MAXPS_LOW3 0x05, 0x64 -#define TM6010_REQ05_R65_OUT_MAXPS_HIGH3 0x05, 0x65 -#define TM6010_REQ05_R66_OUT_MAXPS_LOW4 0x05, 0x66 -#define TM6010_REQ05_R67_OUT_MAXPS_HIGH4 0x05, 0x67 -#define TM6010_REQ05_R68_OUT_MAXPS_LOW5 0x05, 0x68 -#define TM6010_REQ05_R69_OUT_MAXPS_HIGH5 0x05, 0x69 -#define TM6010_REQ05_R6A_OUT_MAXPS_LOW6 0x05, 0x6a -#define TM6010_REQ05_R6B_OUT_MAXPS_HIGH6 0x05, 0x6b -#define TM6010_REQ05_R6C_OUT_MAXPS_LOW7 0x05, 0x6c -#define TM6010_REQ05_R6D_OUT_MAXPS_HIGH7 0x05, 0x6d -#define TM6010_REQ05_R6E_OUT_MAXPS_LOW8 0x05, 0x6e -#define TM6010_REQ05_R6F_OUT_MAXPS_HIGH8 0x05, 0x6f -#define TM6010_REQ05_R70_OUT_MAXPS_LOW9 0x05, 0x70 -#define TM6010_REQ05_R71_OUT_MAXPS_HIGH9 0x05, 0x71 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW10 0x05, 0x72 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH10 0x05, 0x73 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW11 0x05, 0x74 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH11 0x05, 0x75 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW12 0x05, 0x76 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH12 0x05, 0x77 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW13 0x05, 0x78 -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH13 0x05, 0x79 -#define TM6010_REQ05_R60_OUT_MAXPS_LOW14 0x05, 0x7a -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH14 0x05, 0x7b -#define TM6010_REQ05_R60_OUT_MAXPS_LOW15 0x05, 0x7c -#define TM6010_REQ05_R61_OUT_MAXPS_HIGH15 0x05, 0x7d -#define TM6010_REQ05_R80_FIFO0 0x05, 0x80 -#define TM6010_REQ05_R81_FIFO1 0x05, 0x81 -#define TM6010_REQ05_R82_FIFO2 0x05, 0x82 -#define TM6010_REQ05_R83_FIFO3 0x05, 0x83 -#define TM6010_REQ05_R84_FIFO4 0x05, 0x84 -#define TM6010_REQ05_R85_FIFO5 0x05, 0x85 -#define TM6010_REQ05_R86_FIFO6 0x05, 0x86 -#define TM6010_REQ05_R87_FIFO7 0x05, 0x87 -#define TM6010_REQ05_R88_FIFO8 0x05, 0x88 -#define TM6010_REQ05_R89_FIFO9 0x05, 0x89 -#define TM6010_REQ05_R81_FIFO10 0x05, 0x8a -#define TM6010_REQ05_R81_FIFO11 0x05, 0x8b -#define TM6010_REQ05_R81_FIFO12 0x05, 0x8c -#define TM6010_REQ05_R81_FIFO13 0x05, 0x8d -#define TM6010_REQ05_R81_FIFO14 0x05, 0x8e -#define TM6010_REQ05_R81_FIFO15 0x05, 0x8f -#define TM6010_REQ05_R90_CFG_FIFO0 0x05, 0x90 -#define TM6010_REQ05_R91_CFG_FIFO1 0x05, 0x91 -#define TM6010_REQ05_R92_CFG_FIFO2 0x05, 0x92 -#define TM6010_REQ05_R93_CFG_FIFO3 0x05, 0x93 -#define TM6010_REQ05_R94_CFG_FIFO4 0x05, 0x94 -#define TM6010_REQ05_R95_CFG_FIFO5 0x05, 0x95 -#define TM6010_REQ05_R96_CFG_FIFO6 0x05, 0x96 -#define TM6010_REQ05_R97_CFG_FIFO7 0x05, 0x97 -#define TM6010_REQ05_R98_CFG_FIFO8 0x05, 0x98 -#define TM6010_REQ05_R99_CFG_FIFO9 0x05, 0x99 -#define TM6010_REQ05_R91_CFG_FIFO10 0x05, 0x9a -#define TM6010_REQ05_R91_CFG_FIFO11 0x05, 0x9b -#define TM6010_REQ05_R91_CFG_FIFO12 0x05, 0x9c -#define TM6010_REQ05_R91_CFG_FIFO13 0x05, 0x9d -#define TM6010_REQ05_R91_CFG_FIFO14 0x05, 0x9e -#define TM6010_REQ05_R91_CFG_FIFO15 0x05, 0x9f -#define TM6010_REQ05_RA0_CTL_FIFO0 0x05, 0xa0 -#define TM6010_REQ05_RA1_CTL_FIFO1 0x05, 0xa1 -#define TM6010_REQ05_RA2_CTL_FIFO2 0x05, 0xa2 -#define TM6010_REQ05_RA3_CTL_FIFO3 0x05, 0xa3 -#define TM6010_REQ05_RA4_CTL_FIFO4 0x05, 0xa4 -#define TM6010_REQ05_RA5_CTL_FIFO5 0x05, 0xa5 -#define TM6010_REQ05_RA6_CTL_FIFO6 0x05, 0xa6 -#define TM6010_REQ05_RA7_CTL_FIFO7 0x05, 0xa7 -#define TM6010_REQ05_RA8_CTL_FIFO8 0x05, 0xa8 -#define TM6010_REQ05_RA9_CTL_FIFO9 0x05, 0xa9 -#define TM6010_REQ05_RA1_CTL_FIFO10 0x05, 0xaa -#define TM6010_REQ05_RA1_CTL_FIFO11 0x05, 0xab -#define TM6010_REQ05_RA1_CTL_FIFO12 0x05, 0xac -#define TM6010_REQ05_RA1_CTL_FIFO13 0x05, 0xad -#define TM6010_REQ05_RA1_CTL_FIFO14 0x05, 0xae -#define TM6010_REQ05_RA1_CTL_FIFO15 0x05, 0xaf -#define TM6010_REQ05_RB0_BC_LOW_FIFO0 0x05, 0xb0 -#define TM6010_REQ05_RB1_BC_LOW_FIFO1 0x05, 0xb1 -#define TM6010_REQ05_RB2_BC_LOW_FIFO2 0x05, 0xb2 -#define TM6010_REQ05_RB3_BC_LOW_FIFO3 0x05, 0xb3 -#define TM6010_REQ05_RB4_BC_LOW_FIFO4 0x05, 0xb4 -#define TM6010_REQ05_RB5_BC_LOW_FIFO5 0x05, 0xb5 -#define TM6010_REQ05_RB6_BC_LOW_FIFO6 0x05, 0xb6 -#define TM6010_REQ05_RB7_BC_LOW_FIFO7 0x05, 0xb7 -#define TM6010_REQ05_RB8_BC_LOW_FIFO8 0x05, 0xb8 -#define TM6010_REQ05_RB9_BC_LOW_FIFO9 0x05, 0xb9 -#define TM6010_REQ05_RB1_BC_LOW_FIFO10 0x05, 0xba -#define TM6010_REQ05_RB1_BC_LOW_FIFO11 0x05, 0xbb -#define TM6010_REQ05_RB1_BC_LOW_FIFO12 0x05, 0xbc -#define TM6010_REQ05_RB1_BC_LOW_FIFO13 0x05, 0xbd -#define TM6010_REQ05_RB1_BC_LOW_FIFO14 0x05, 0xbe -#define TM6010_REQ05_RB1_BC_LOW_FIFO15 0x05, 0xbf -#define TM6010_REQ05_RC0_DATA_FIFO0 0x05, 0xc0 -#define TM6010_REQ05_RC4_DATA_FIFO1 0x05, 0xc4 -#define TM6010_REQ05_RC8_DATA_FIFO2 0x05, 0xc8 -#define TM6010_REQ05_RCC_DATA_FIFO3 0x05, 0xcc -#define TM6010_REQ05_RD0_DATA_FIFO4 0x05, 0xd0 -#define TM6010_REQ05_RD4_DATA_FIFO5 0x05, 0xd4 -#define TM6010_REQ05_RD8_DATA_FIFO6 0x05, 0xd8 -#define TM6010_REQ05_RDC_DATA_FIFO7 0x05, 0xdc -#define TM6010_REQ05_RE0_DATA_FIFO8 0x05, 0xe0 -#define TM6010_REQ05_RE4_DATA_FIFO9 0x05, 0xe4 -#define TM6010_REQ05_RC4_DATA_FIFO10 0x05, 0xe8 -#define TM6010_REQ05_RC4_DATA_FIFO11 0x05, 0xec -#define TM6010_REQ05_RC4_DATA_FIFO12 0x05, 0xf0 -#define TM6010_REQ05_RC4_DATA_FIFO13 0x05, 0xf4 -#define TM6010_REQ05_RC4_DATA_FIFO14 0x05, 0xf8 -#define TM6010_REQ05_RC4_DATA_FIFO15 0x05, 0xfc - -/* Define TM6010 Audio decoder registers */ -/* This core available only in TM6010 */ -#define TM6010_REQ08_R00_A_VERSION 0x08, 0x00 -#define TM6010_REQ08_R01_A_INIT 0x08, 0x01 -#define TM6010_REQ08_R02_A_FIX_GAIN_CTRL 0x08, 0x02 -#define TM6010_REQ08_R03_A_AUTO_GAIN_CTRL 0x08, 0x03 -#define TM6010_REQ08_R04_A_SIF_AMP_CTRL 0x08, 0x04 -#define TM6010_REQ08_R05_A_STANDARD_MOD 0x08, 0x05 -#define TM6010_REQ08_R06_A_SOUND_MOD 0x08, 0x06 -#define TM6010_REQ08_R07_A_LEFT_VOL 0x08, 0x07 -#define TM6010_REQ08_R08_A_RIGHT_VOL 0x08, 0x08 -#define TM6010_REQ08_R09_A_MAIN_VOL 0x08, 0x09 -#define TM6010_REQ08_R0A_A_I2S_MOD 0x08, 0x0a -#define TM6010_REQ08_R0B_A_ASD_THRES1 0x08, 0x0b -#define TM6010_REQ08_R0C_A_ASD_THRES2 0x08, 0x0c -#define TM6010_REQ08_R0D_A_AMD_THRES 0x08, 0x0d -#define TM6010_REQ08_R0E_A_MONO_THRES1 0x08, 0x0e -#define TM6010_REQ08_R0F_A_MONO_THRES2 0x08, 0x0f -#define TM6010_REQ08_R10_A_MUTE_THRES1 0x08, 0x10 -#define TM6010_REQ08_R11_A_MUTE_THRES2 0x08, 0x11 -#define TM6010_REQ08_R12_A_AGC_U 0x08, 0x12 -#define TM6010_REQ08_R13_A_AGC_ERR_T 0x08, 0x13 -#define TM6010_REQ08_R14_A_AGC_GAIN_INIT 0x08, 0x14 -#define TM6010_REQ08_R15_A_AGC_STEP_THR 0x08, 0x15 -#define TM6010_REQ08_R16_A_AGC_GAIN_MAX 0x08, 0x16 -#define TM6010_REQ08_R17_A_AGC_GAIN_MIN 0x08, 0x17 -#define TM6010_REQ08_R18_A_TR_CTRL 0x08, 0x18 -#define TM6010_REQ08_R19_A_FH_2FH_GAIN 0x08, 0x19 -#define TM6010_REQ08_R1A_A_NICAM_SER_MAX 0x08, 0x1a -#define TM6010_REQ08_R1B_A_NICAM_SER_MIN 0x08, 0x1b -#define TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT 0x08, 0x1e -#define TM6010_REQ08_R1F_A_TEST_INTF_SEL 0x08, 0x1f -#define TM6010_REQ08_R20_A_TEST_PIN_SEL 0x08, 0x20 -#define TM6010_REQ08_R21_A_AGC_ERR 0x08, 0x21 -#define TM6010_REQ08_R22_A_AGC_GAIN 0x08, 0x22 -#define TM6010_REQ08_R23_A_NICAM_INFO 0x08, 0x23 -#define TM6010_REQ08_R24_A_SER 0x08, 0x24 -#define TM6010_REQ08_R25_A_C1_AMP 0x08, 0x25 -#define TM6010_REQ08_R26_A_C2_AMP 0x08, 0x26 -#define TM6010_REQ08_R27_A_NOISE_AMP 0x08, 0x27 -#define TM6010_REQ08_R28_A_AUDIO_MODE_RES 0x08, 0x28 - -/* Define TM6010 Video ADC registers */ -#define TM6010_REQ08_RE0_ADC_REF 0x08, 0xe0 -#define TM6010_REQ08_RE1_DAC_CLMP 0x08, 0xe1 -#define TM6010_REQ08_RE2_POWER_DOWN_CTRL1 0x08, 0xe2 -#define TM6010_REQ08_RE3_ADC_IN1_SEL 0x08, 0xe3 -#define TM6010_REQ08_RE4_ADC_IN2_SEL 0x08, 0xe4 -#define TM6010_REQ08_RE5_GAIN_PARAM 0x08, 0xe5 -#define TM6010_REQ08_RE6_POWER_DOWN_CTRL2 0x08, 0xe6 -#define TM6010_REQ08_RE7_REG_GAIN_Y 0x08, 0xe7 -#define TM6010_REQ08_RE8_REG_GAIN_C 0x08, 0xe8 -#define TM6010_REQ08_RE9_BIAS_CTRL 0x08, 0xe9 -#define TM6010_REQ08_REA_BUFF_DRV_CTRL 0x08, 0xea -#define TM6010_REQ08_REB_SIF_GAIN_CTRL 0x08, 0xeb -#define TM6010_REQ08_REC_REVERSE_YC_CTRL 0x08, 0xec -#define TM6010_REQ08_RED_GAIN_SEL 0x08, 0xed - -/* Define TM6010 Audio ADC registers */ -#define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG 0x08, 0xf0 -#define TM6010_REQ08_RF1_AADC_POWER_DOWN 0x08, 0xf1 -#define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL 0x08, 0xf2 -#define TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL 0x08, 0xf3 diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-stds.c b/drivers/staging/media/deprecated/tm6000/tm6000-stds.c deleted file mode 100644 index 858cb4f3a9ca..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-stds.c +++ /dev/null @@ -1,623 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices -// -// Copyright (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org> - -#include <linux/module.h> -#include <linux/kernel.h> -#include "tm6000.h" -#include "tm6000-regs.h" - -static unsigned int tm6010_a_mode; -module_param(tm6010_a_mode, int, 0644); -MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode"); - -struct tm6000_reg_settings { - unsigned char req; - unsigned char reg; - unsigned char value; -}; - - -struct tm6000_std_settings { - v4l2_std_id id; - struct tm6000_reg_settings *common; -}; - -static struct tm6000_reg_settings composite_pal_m[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x04 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x20 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_pal_nc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x36 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_pal[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x32 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_secam[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x38 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x02 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2c }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings composite_ntsc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_std_settings composite_stds[] = { - { .id = V4L2_STD_PAL_M, .common = composite_pal_m, }, - { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, }, - { .id = V4L2_STD_PAL, .common = composite_pal, }, - { .id = V4L2_STD_SECAM, .common = composite_secam, }, - { .id = V4L2_STD_NTSC, .common = composite_ntsc, }, -}; - -static struct tm6000_reg_settings svideo_pal_m[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x05 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x83 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x0a }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe0 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_pal_nc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x37 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x91 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x1f }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x0c }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_pal[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x33 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x04 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x25 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0xd5 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0x63 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0x50 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x0c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x52 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdc }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_secam[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x39 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0e }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x31 }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x24 }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x92 }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xe8 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xed }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x8c }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x2a }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0xc1 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x2c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x18 }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0xff }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_reg_settings svideo_ntsc[] = { - { TM6010_REQ07_R3F_RESET, 0x01 }, - { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x01 }, - { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x0f }, - { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, - { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x03 }, - { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x30 }, - { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0x8b }, - { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, - { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, - { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, - { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, - { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, - { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, - { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, - { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, - { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, - { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, - { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, - { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, - { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, - { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, - { TM6010_REQ07_R83_CHROMA_LOCK_CONFIG, 0x6f }, - { TM6010_REQ07_R04_LUMA_HAGC_CONTROL, 0xdd }, - { TM6010_REQ07_R0D_CHROMA_KILL_LEVEL, 0x07 }, - { TM6010_REQ07_R3F_RESET, 0x00 }, - { 0, 0, 0 } -}; - -static struct tm6000_std_settings svideo_stds[] = { - { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, }, - { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, }, - { .id = V4L2_STD_PAL, .common = svideo_pal, }, - { .id = V4L2_STD_SECAM, .common = svideo_secam, }, - { .id = V4L2_STD_NTSC, .common = svideo_ntsc, }, -}; - -static int tm6000_set_audio_std(struct tm6000_core *dev) -{ - uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */ - uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */ - uint8_t areg_06 = 0x02; /* Auto de-emphasis, manual channel mode */ - - if (dev->radio) { - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04); - tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c); - /* set mono or stereo */ - if (dev->amode == V4L2_TUNER_MODE_MONO) - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); - else if (dev->amode == V4L2_TUNER_MODE_STEREO) - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x02); - tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18); - tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a); - tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40); - tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); - tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0xff); - return 0; - } - - /* - * STD/MN shouldn't be affected by tm6010_a_mode, as there's just one - * audio standard for each V4L2_STD type. - */ - if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_KR) { - areg_05 |= 0x04; - } else if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_JP) { - areg_05 |= 0x43; - } else if (dev->norm & V4L2_STD_MN) { - areg_05 |= 0x22; - } else switch (tm6010_a_mode) { - /* auto */ - case 0: - if ((dev->norm & V4L2_STD_SECAM) == V4L2_STD_SECAM_L) - areg_05 |= 0x00; - else /* Other PAL/SECAM standards */ - areg_05 |= 0x10; - break; - /* A2 */ - case 1: - if (dev->norm & V4L2_STD_DK) - areg_05 = 0x09; - else - areg_05 = 0x05; - break; - /* NICAM */ - case 2: - if (dev->norm & V4L2_STD_DK) { - areg_05 = 0x06; - } else if (dev->norm & V4L2_STD_PAL_I) { - areg_05 = 0x08; - } else if (dev->norm & V4L2_STD_SECAM_L) { - areg_05 = 0x0a; - areg_02 = 0x02; - } else { - areg_05 = 0x07; - } - break; - /* other */ - case 3: - if (dev->norm & V4L2_STD_DK) { - areg_05 = 0x0b; - } else { - areg_05 = 0x02; - } - break; - } - - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, areg_02); - tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0); - tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, areg_05); - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, areg_06); - tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08); - tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91); - tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12); - tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0); - tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0); - tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80); - tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12); - tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20); - tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14); - tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01); - tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0); - tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32); - tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64); - tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20); - tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00); - tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); - tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); - - return 0; -} - -void tm6000_get_std_res(struct tm6000_core *dev) -{ - /* Currently, those are the only supported resoltions */ - if (dev->norm & V4L2_STD_525_60) - dev->height = 480; - else - dev->height = 576; - - dev->width = 720; -} - -static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set) -{ - int i, rc; - - /* Load board's initialization table */ - for (i = 0; set[i].req; i++) { - rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value); - if (rc < 0) { - printk(KERN_ERR "Error %i while setting req %d, reg %d to value %d\n", - rc, set[i].req, set[i].reg, set[i].value); - return rc; - } - } - - return 0; -} - -int tm6000_set_standard(struct tm6000_core *dev) -{ - struct tm6000_input *input; - int i, rc = 0; - u8 reg_07_fe = 0x8a; - u8 reg_08_f1 = 0xfc; - u8 reg_08_e2 = 0xf0; - u8 reg_08_e6 = 0x0f; - - tm6000_get_std_res(dev); - - if (!dev->radio) - input = &dev->vinput[dev->input]; - else - input = &dev->rinput; - - if (dev->dev_type == TM6010) { - switch (input->vmux) { - case TM6000_VMUX_VIDEO_A: - tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4); - tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1); - tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0); - tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); - tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8); - reg_07_fe |= 0x01; - break; - case TM6000_VMUX_VIDEO_B: - tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf8); - tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf1); - tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xe0); - tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); - tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe8); - reg_07_fe |= 0x01; - break; - case TM6000_VMUX_VIDEO_AB: - tm6000_set_reg(dev, TM6010_REQ08_RE3_ADC_IN1_SEL, 0xfc); - tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8); - reg_08_e6 = 0x00; - tm6000_set_reg(dev, TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2); - tm6000_set_reg(dev, TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0); - tm6000_set_reg(dev, TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2); - tm6000_set_reg(dev, TM6010_REQ08_RED_GAIN_SEL, 0xe0); - break; - default: - break; - } - switch (input->amux) { - case TM6000_AMUX_ADC1: - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x00, 0x0f); - /* Mux overflow workaround */ - tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, - 0x10, 0xf0); - break; - case TM6000_AMUX_ADC2: - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x08, 0x0f); - /* Mux overflow workaround */ - tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, - 0x10, 0xf0); - break; - case TM6000_AMUX_SIF1: - reg_08_e2 |= 0x02; - reg_08_e6 = 0x08; - reg_07_fe |= 0x40; - reg_08_f1 |= 0x02; - tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3); - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x02, 0x0f); - /* Mux overflow workaround */ - tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, - 0x30, 0xf0); - break; - case TM6000_AMUX_SIF2: - reg_08_e2 |= 0x02; - reg_08_e6 = 0x08; - reg_07_fe |= 0x40; - reg_08_f1 |= 0x02; - tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7); - tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x02, 0x0f); - /* Mux overflow workaround */ - tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, - 0x30, 0xf0); - break; - default: - break; - } - tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, reg_08_e2); - tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, reg_08_e6); - tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, reg_08_f1); - tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, reg_07_fe); - } else { - switch (input->vmux) { - case TM6000_VMUX_VIDEO_A: - tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); - tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); - tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); - break; - case TM6000_VMUX_VIDEO_B: - tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00); - tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x0f); - tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0); - break; - case TM6000_VMUX_VIDEO_AB: - tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10); - tm6000_set_reg(dev, TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x10); - tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00); - tm6000_set_reg(dev, - REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1); - break; - default: - break; - } - switch (input->amux) { - case TM6000_AMUX_ADC1: - tm6000_set_reg_mask(dev, - TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f); - break; - case TM6000_AMUX_ADC2: - tm6000_set_reg_mask(dev, - TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f); - break; - default: - break; - } - } - if (input->type == TM6000_INPUT_SVIDEO) { - for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) { - if (dev->norm & svideo_stds[i].id) { - rc = tm6000_load_std(dev, svideo_stds[i].common); - goto ret; - } - } - return -EINVAL; - } else { - for (i = 0; i < ARRAY_SIZE(composite_stds); i++) { - if (dev->norm & composite_stds[i].id) { - rc = tm6000_load_std(dev, composite_stds[i].common); - goto ret; - } - } - return -EINVAL; - } - -ret: - if (rc < 0) - return rc; - - if ((dev->dev_type == TM6010) && - ((input->amux == TM6000_AMUX_SIF1) || - (input->amux == TM6000_AMUX_SIF2))) - tm6000_set_audio_std(dev); - - msleep(40); - - return 0; -} diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h b/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h deleted file mode 100644 index e3c6933f854d..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> - */ - -#include <linux/videodev2.h> - -#define TM6000_URB_MSG_LEN 180 - -struct usb_isoc_ctl { - /* max packet size of isoc transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for isoc transfers */ - struct urb **urb; - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int vfield, field; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct tm6000_buffer *buf; -}; diff --git a/drivers/staging/media/deprecated/tm6000/tm6000-video.c b/drivers/staging/media/deprecated/tm6000/tm6000-video.c deleted file mode 100644 index e06ed21edbdd..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000-video.c +++ /dev/null @@ -1,1703 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// tm6000-video.c - driver for TM5600/TM6000/TM6010 USB video capture devices -// -// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> -// -// Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com> -// - Fixed module load/unload - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/random.h> -#include <linux/usb.h> -#include <linux/videodev2.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-event.h> -#include <media/tuner.h> -#include <linux/interrupt.h> -#include <linux/kthread.h> -#include <linux/highmem.h> -#include <linux/freezer.h> - -#include "tm6000-regs.h" -#include "tm6000.h" - -#define BUFFER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ - -/* Limits minimum and default number of buffers */ -#define TM6000_MIN_BUF 4 -#define TM6000_DEF_BUF 8 - -#define TM6000_NUM_URB_BUF 8 - -#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */ - -/* Declare static vars that will be used as parameters */ -static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ -static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ -static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */ -static bool keep_urb; /* keep urb buffers allocated */ - -/* Debug level */ -int tm6000_debug; -EXPORT_SYMBOL_GPL(tm6000_debug); - -static struct tm6000_fmt format[] = { - { - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - }, { - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - }, { - .fourcc = V4L2_PIX_FMT_TM6000, - .depth = 16, - } -}; - -/* ------------------------------------------------------------------ - * DMA and thread functions - * ------------------------------------------------------------------ - */ - -#define norm_maxw(a) 720 -#define norm_maxh(a) 576 - -#define norm_minw(a) norm_maxw(a) -#define norm_minh(a) norm_maxh(a) - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_buf(struct tm6000_dmaqueue *dma_q, - struct tm6000_buffer **buf) -{ - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - - if (list_empty(&dma_q->active)) { - dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n"); - *buf = NULL; - return; - } - - *buf = list_entry(dma_q->active.next, - struct tm6000_buffer, vb.queue); -} - -/* - * Announces that a buffer were filled and request the next - */ -static inline void buffer_filled(struct tm6000_core *dev, - struct tm6000_dmaqueue *dma_q, - struct tm6000_buffer *buf) -{ - /* Advice that buffer was filled */ - dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - buf->vb.ts = ktime_get_ns(); - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -/* - * Identify the tm5600/6000 buffer header type and properly handles - */ -static int copy_streams(u8 *data, unsigned long len, - struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - u8 *ptr = data, *endp = data+len; - unsigned long header = 0; - int rc = 0; - unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0; - struct tm6000_buffer *vbuf = NULL; - char *voutp = NULL; - unsigned int linewidth; - - if (!dev->radio) { - /* get video buffer */ - get_next_buf(dma_q, &vbuf); - - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - - if (!voutp) - return 0; - } - - for (ptr = data; ptr < endp;) { - if (!dev->isoc_ctl.cmd) { - /* Header */ - if (dev->isoc_ctl.tmp_buf_len > 0) { - /* from last urb or packet */ - header = dev->isoc_ctl.tmp_buf; - if (4 - dev->isoc_ctl.tmp_buf_len > 0) { - memcpy((u8 *)&header + - dev->isoc_ctl.tmp_buf_len, - ptr, - 4 - dev->isoc_ctl.tmp_buf_len); - ptr += 4 - dev->isoc_ctl.tmp_buf_len; - } - dev->isoc_ctl.tmp_buf_len = 0; - } else { - if (ptr + 3 >= endp) { - /* have incomplete header */ - dev->isoc_ctl.tmp_buf_len = endp - ptr; - memcpy(&dev->isoc_ctl.tmp_buf, ptr, - dev->isoc_ctl.tmp_buf_len); - return rc; - } - /* Seek for sync */ - for (; ptr < endp - 3; ptr++) { - if (*(ptr + 3) == 0x47) - break; - } - /* Get message header */ - header = *(unsigned long *)ptr; - ptr += 4; - } - - /* split the header fields */ - size = ((header & 0x7e) << 1); - if (size > 0) - size -= 4; - block = (header >> 7) & 0xf; - field = (header >> 11) & 0x1; - line = (header >> 12) & 0x1ff; - cmd = (header >> 21) & 0x7; - /* Validates header fields */ - if (size > TM6000_URB_MSG_LEN) - size = TM6000_URB_MSG_LEN; - pktsize = TM6000_URB_MSG_LEN; - /* - * calculate position in buffer and change the buffer - */ - switch (cmd) { - case TM6000_URB_MSG_VIDEO: - if (!dev->radio) { - if ((dev->isoc_ctl.vfield != field) && - (field == 1)) { - /* - * Announces that a new buffer - * were filled - */ - buffer_filled(dev, dma_q, vbuf); - dprintk(dev, V4L2_DEBUG_ISOC, - "new buffer filled\n"); - get_next_buf(dma_q, &vbuf); - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - if (!voutp) - return rc; - memset(voutp, 0, vbuf->vb.size); - } - linewidth = vbuf->vb.width << 1; - pos = ((line << 1) - field - 1) * - linewidth + block * TM6000_URB_MSG_LEN; - /* Don't allow to write out of the buffer */ - if (pos + size > vbuf->vb.size) - cmd = TM6000_URB_MSG_ERR; - dev->isoc_ctl.vfield = field; - } - break; - case TM6000_URB_MSG_VBI: - break; - case TM6000_URB_MSG_AUDIO: - case TM6000_URB_MSG_PTS: - size = pktsize; /* Size is always 180 bytes */ - break; - } - } else { - /* Continue the last copy */ - cmd = dev->isoc_ctl.cmd; - size = dev->isoc_ctl.size; - pos = dev->isoc_ctl.pos; - pktsize = dev->isoc_ctl.pktsize; - field = dev->isoc_ctl.field; - } - cpysize = (endp - ptr > size) ? size : endp - ptr; - if (cpysize) { - /* copy data in different buffers */ - switch (cmd) { - case TM6000_URB_MSG_VIDEO: - /* Fills video buffer */ - if (vbuf) - memcpy(&voutp[pos], ptr, cpysize); - break; - case TM6000_URB_MSG_AUDIO: { - int i; - for (i = 0; i < cpysize; i += 2) - swab16s((u16 *)(ptr + i)); - - tm6000_call_fillbuf(dev, TM6000_AUDIO, ptr, cpysize); - break; - } - case TM6000_URB_MSG_VBI: - /* Need some code to copy vbi buffer */ - break; - case TM6000_URB_MSG_PTS: { - /* Need some code to copy pts */ - u32 pts; - pts = *(u32 *)ptr; - dprintk(dev, V4L2_DEBUG_ISOC, "field %d, PTS %x", - field, pts); - break; - } - } - } - if (ptr + pktsize > endp) { - /* - * End of URB packet, but cmd processing is not - * complete. Preserve the state for a next packet - */ - dev->isoc_ctl.pos = pos + cpysize; - dev->isoc_ctl.size = size - cpysize; - dev->isoc_ctl.cmd = cmd; - dev->isoc_ctl.field = field; - dev->isoc_ctl.pktsize = pktsize - (endp - ptr); - ptr += endp - ptr; - } else { - dev->isoc_ctl.cmd = 0; - ptr += pktsize; - } - } - return 0; -} - -/* - * Identify the tm5600/6000 buffer header type and properly handles - */ -static int copy_multiplexed(u8 *ptr, unsigned long len, - struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - unsigned int pos = dev->isoc_ctl.pos, cpysize; - int rc = 1; - struct tm6000_buffer *buf; - char *outp = NULL; - - get_next_buf(dma_q, &buf); - if (buf) - outp = videobuf_to_vmalloc(&buf->vb); - - if (!outp) - return 0; - - while (len > 0) { - cpysize = min(len, buf->vb.size-pos); - memcpy(&outp[pos], ptr, cpysize); - pos += cpysize; - ptr += cpysize; - len -= cpysize; - if (pos >= buf->vb.size) { - pos = 0; - /* Announces that a new buffer were filled */ - buffer_filled(dev, dma_q, buf); - dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - get_next_buf(dma_q, &buf); - if (!buf) - break; - outp = videobuf_to_vmalloc(&(buf->vb)); - if (!outp) - return rc; - pos = 0; - } - } - - dev->isoc_ctl.pos = pos; - return rc; -} - -static inline void print_err_status(struct tm6000_core *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(dev, V4L2_DEBUG_QUEUE, "URB status %d [%s].\n", - status, errmsg); - } else { - dprintk(dev, V4L2_DEBUG_QUEUE, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - - -/* - * Controls the isoc copy of each urb packet - */ -static inline int tm6000_isoc_copy(struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - int i, len = 0, rc = 1, status; - char *p; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - return 0; - } - - for (i = 0; i < urb->number_of_packets; i++) { - status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - continue; - } - - len = urb->iso_frame_desc[i].actual_length; - - if (len > 0) { - p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (!urb->iso_frame_desc[i].status) { - if ((dev->fourcc) == V4L2_PIX_FMT_TM6000) { - rc = copy_multiplexed(p, len, urb); - if (rc <= 0) - return rc; - } else { - copy_streams(p, len, urb); - } - } - } - } - return rc; -} - -/* ------------------------------------------------------------------ - * URB control - * ------------------------------------------------------------------ - */ - -/* - * IRQ callback, called by URB callback - */ -static void tm6000_irq_callback(struct urb *urb) -{ - struct tm6000_dmaqueue *dma_q = urb->context; - struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq); - unsigned long flags; - int i; - - switch (urb->status) { - case 0: - case -ETIMEDOUT: - break; - - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - - default: - tm6000_err("urb completion error %d.\n", urb->status); - break; - } - - spin_lock_irqsave(&dev->slock, flags); - tm6000_isoc_copy(urb); - spin_unlock_irqrestore(&dev->slock, flags); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) - tm6000_err("urb resubmit failed (error=%i)\n", - urb->status); -} - -/* - * Allocate URB buffers - */ -static int tm6000_alloc_urb_buffers(struct tm6000_core *dev) -{ - int num_bufs = TM6000_NUM_URB_BUF; - int i; - - if (dev->urb_buffer) - return 0; - - dev->urb_buffer = kmalloc_array(num_bufs, sizeof(*dev->urb_buffer), - GFP_KERNEL); - if (!dev->urb_buffer) - return -ENOMEM; - - dev->urb_dma = kmalloc_array(num_bufs, sizeof(*dev->urb_dma), - GFP_KERNEL); - if (!dev->urb_dma) - return -ENOMEM; - - for (i = 0; i < num_bufs; i++) { - dev->urb_buffer[i] = usb_alloc_coherent( - dev->udev, dev->urb_size, - GFP_KERNEL, &dev->urb_dma[i]); - if (!dev->urb_buffer[i]) { - tm6000_err("unable to allocate %i bytes for transfer buffer %i\n", - dev->urb_size, i); - return -ENOMEM; - } - memset(dev->urb_buffer[i], 0, dev->urb_size); - } - - return 0; -} - -/* - * Free URB buffers - */ -static int tm6000_free_urb_buffers(struct tm6000_core *dev) -{ - int i; - - if (!dev->urb_buffer) - return 0; - - for (i = 0; i < TM6000_NUM_URB_BUF; i++) { - if (dev->urb_buffer[i]) { - usb_free_coherent(dev->udev, - dev->urb_size, - dev->urb_buffer[i], - dev->urb_dma[i]); - dev->urb_buffer[i] = NULL; - } - } - kfree(dev->urb_buffer); - kfree(dev->urb_dma); - dev->urb_buffer = NULL; - dev->urb_dma = NULL; - - return 0; -} - -/* - * Stop and Deallocate URBs - */ -static void tm6000_uninit_isoc(struct tm6000_core *dev) -{ - struct urb *urb; - int i; - - dev->isoc_ctl.buf = NULL; - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = dev->isoc_ctl.urb[i]; - if (urb) { - usb_kill_urb(urb); - usb_unlink_urb(urb); - usb_free_urb(urb); - dev->isoc_ctl.urb[i] = NULL; - } - dev->isoc_ctl.transfer_buffer[i] = NULL; - } - - if (!keep_urb) - tm6000_free_urb_buffers(dev); - - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - - dev->isoc_ctl.urb = NULL; - dev->isoc_ctl.transfer_buffer = NULL; - dev->isoc_ctl.num_bufs = 0; -} - -/* - * Assign URBs and start IRQ - */ -static int tm6000_prepare_isoc(struct tm6000_core *dev) -{ - struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i, j, sb_size, pipe, size, max_packets; - int num_bufs = TM6000_NUM_URB_BUF; - struct urb *urb; - - /* De-allocates all pending stuff */ - tm6000_uninit_isoc(dev); - /* Stop interrupt USB pipe */ - tm6000_ir_int_stop(dev); - - usb_set_interface(dev->udev, - dev->isoc_in.bInterfaceNumber, - dev->isoc_in.bAlternateSetting); - - /* Start interrupt USB pipe */ - tm6000_ir_int_start(dev); - - pipe = usb_rcvisocpipe(dev->udev, - dev->isoc_in.endp->desc.bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe); - - if (size > dev->isoc_in.maxsize) - size = dev->isoc_in.maxsize; - - dev->isoc_ctl.max_pkt_size = size; - - max_packets = TM6000_MAX_ISO_PACKETS; - sb_size = max_packets * size; - dev->urb_size = sb_size; - - dev->isoc_ctl.num_bufs = num_bufs; - - dev->isoc_ctl.urb = kmalloc_array(num_bufs, sizeof(void *), - GFP_KERNEL); - if (!dev->isoc_ctl.urb) - return -ENOMEM; - - dev->isoc_ctl.transfer_buffer = kmalloc_array(num_bufs, - sizeof(void *), - GFP_KERNEL); - if (!dev->isoc_ctl.transfer_buffer) { - kfree(dev->isoc_ctl.urb); - return -ENOMEM; - } - - dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets (%d bytes) of %d bytes each to handle %u size\n", - max_packets, num_bufs, sb_size, - dev->isoc_in.maxsize, size); - - - if (tm6000_alloc_urb_buffers(dev) < 0) { - tm6000_err("cannot allocate memory for urb buffers\n"); - - /* call free, as some buffers might have been allocated */ - tm6000_free_urb_buffers(dev); - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - return -ENOMEM; - } - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - tm6000_uninit_isoc(dev); - tm6000_free_urb_buffers(dev); - return -ENOMEM; - } - dev->isoc_ctl.urb[i] = urb; - - urb->transfer_dma = dev->urb_dma[i]; - dev->isoc_ctl.transfer_buffer[i] = dev->urb_buffer[i]; - - usb_fill_bulk_urb(urb, dev->udev, pipe, - dev->isoc_ctl.transfer_buffer[i], sb_size, - tm6000_irq_callback, dma_q); - urb->interval = dev->isoc_in.endp->desc.bInterval; - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = size * j; - urb->iso_frame_desc[j].length = size; - } - } - - return 0; -} - -static int tm6000_start_thread(struct tm6000_core *dev) -{ - struct tm6000_dmaqueue *dma_q = &dev->vidq; - int i; - - dma_q->frame = 0; - dma_q->ini_jiffies = jiffies; - - init_waitqueue_head(&dma_q->wq); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - int rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); - if (rc) { - tm6000_err("submit of urb %i failed (error=%i)\n", i, - rc); - tm6000_uninit_isoc(dev); - return rc; - } - } - - return 0; -} - -/* ------------------------------------------------------------------ - * Videobuf operations - * ------------------------------------------------------------------ - */ - -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) -{ - struct tm6000_fh *fh = vq->priv_data; - - *size = fh->fmt->depth * fh->width * fh->height >> 3; - if (0 == *count) - *count = TM6000_DEF_BUF; - - if (*count < TM6000_MIN_BUF) - *count = TM6000_MIN_BUF; - - while (*size * *count > vid_limit * 1024 * 1024) - (*count)--; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf) -{ - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_core *dev = fh->dev; - unsigned long flags; - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.buf == buf) - dev->isoc_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - struct tm6000_core *dev = fh->dev; - int rc = 0; - - BUG_ON(NULL == fh->fmt); - - - /* FIXME: It assumes depth=2 */ - /* The only currently supported format is 16 bits/pixel */ - buf->vb.size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - buf->vb.state = VIDEOBUF_NEEDS_INIT; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc != 0) - goto fail; - } - - if (!dev->isoc_ctl.num_bufs) { - rc = tm6000_prepare_isoc(dev); - if (rc < 0) - goto fail; - - rc = tm6000_start_thread(dev); - if (rc < 0) - goto fail; - - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - struct tm6000_fh *fh = vq->priv_data; - struct tm6000_core *dev = fh->dev; - struct tm6000_dmaqueue *vidq = &dev->vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); -} - -static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct tm6000_buffer *buf = container_of(vb, struct tm6000_buffer, vb); - - free_buffer(vq, buf); -} - -static const struct videobuf_queue_ops tm6000_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ - * IOCTL handling - * ------------------------------------------------------------------ - */ - -static bool is_res_read(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh && dev->is_res_read) - return true; - - return false; -} - -static bool is_res_streaming(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh) - return true; - - return false; -} - -static bool res_get(struct tm6000_core *dev, struct tm6000_fh *fh, - bool is_res_read) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources == fh && dev->is_res_read == is_res_read) - return true; - - /* is it free? */ - if (dev->resources) - return false; - - /* grab it */ - dev->resources = fh; - dev->is_res_read = is_res_read; - dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: get\n"); - return true; -} - -static void res_free(struct tm6000_core *dev, struct tm6000_fh *fh) -{ - /* Is the current fh handling it? if so, that's OK */ - if (dev->resources != fh) - return; - - dev->resources = NULL; - dprintk(dev, V4L2_DEBUG_RES_LOCK, "res: put\n"); -} - -/* ------------------------------------------------------------------ - * IOCTL vidioc handling - * ------------------------------------------------------------------ - */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; - - strscpy(cap->driver, "tm6000", sizeof(cap->driver)); - strscpy(cap->card, "Trident TM5600/6000/6010", sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_DEVICE_CAPS; - if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - if (dev->caps.has_radio) - cap->capabilities |= V4L2_CAP_RADIO; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index >= ARRAY_SIZE(format)) - return -EINVAL; - - f->pixelformat = format[f->index].fourcc; - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vb_vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static struct tm6000_fmt *format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(format); i++) - if (format[i].fourcc == fourcc) - return format+i; - return NULL; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; - struct tm6000_fmt *fmt; - enum v4l2_field field; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) { - dprintk(dev, 2, "Fourcc format (0x%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - field = V4L2_FIELD_INTERLACED; - - tm6000_get_std_res(dev); - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - - f->fmt.pix.width &= ~0x01; - - f->fmt.pix.field = field; - - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - return 0; -} - -/*FIXME: This seems to be generic enough to be at videodev2 */ -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int ret = vidioc_try_fmt_vid_cap(file, fh, f); - if (ret < 0) - return ret; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vb_vidq.field = f->fmt.pix.field; - fh->type = f->type; - - dev->fourcc = f->fmt.pix.pixelformat; - - tm6000_set_fourcc_format(dev); - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_reqbufs(&fh->vb_vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_querybuf(&fh->vb_vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_qbuf(&fh->vb_vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct tm6000_fh *fh = priv; - - return videobuf_dqbuf(&fh->vb_vidq, p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - if (!res_get(dev, fh, false)) - return -EBUSY; - return videobuf_streamon(&fh->vb_vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (i != fh->type) - return -EINVAL; - - videobuf_streamoff(&fh->vb_vidq); - res_free(dev, fh); - - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) -{ - int rc = 0; - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - dev->norm = norm; - rc = tm6000_init_analog_mode(dev); - - fh->width = dev->width; - fh->height = dev->height; - - if (rc < 0) - return rc; - - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); - - return 0; -} - -static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - *norm = dev->norm; - return 0; -} - -static const char *iname[] = { - [TM6000_INPUT_TV] = "Television", - [TM6000_INPUT_COMPOSITE1] = "Composite 1", - [TM6000_INPUT_COMPOSITE2] = "Composite 2", - [TM6000_INPUT_SVIDEO] = "S-Video", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= 3) - return -EINVAL; - - if (!dev->vinput[n].type) - return -EINVAL; - - i->index = n; - - if (dev->vinput[n].type == TM6000_INPUT_TV) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - strscpy(i->name, iname[dev->vinput[n].type], sizeof(i->name)); - - i->std = TM6000_STD; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - *i = dev->input; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - int rc = 0; - - if (i >= 3) - return -EINVAL; - if (!dev->vinput[i].type) - return -EINVAL; - - dev->input = i; - - rc = vidioc_s_std(file, priv, dev->norm); - - return rc; -} - -/* --- controls ---------------------------------------------- */ - -static int tm6000_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct tm6000_core *dev = container_of(ctrl->handler, struct tm6000_core, ctrl_handler); - u8 val = ctrl->val; - - switch (ctrl->id) { - case V4L2_CID_CONTRAST: - tm6000_set_reg(dev, TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, val); - return 0; - case V4L2_CID_BRIGHTNESS: - tm6000_set_reg(dev, TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, val); - return 0; - case V4L2_CID_SATURATION: - tm6000_set_reg(dev, TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, val); - return 0; - case V4L2_CID_HUE: - tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val); - return 0; - } - return -EINVAL; -} - -static const struct v4l2_ctrl_ops tm6000_ctrl_ops = { - .s_ctrl = tm6000_s_ctrl, -}; - -static int tm6000_radio_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct tm6000_core *dev = container_of(ctrl->handler, - struct tm6000_core, radio_ctrl_handler); - u8 val = ctrl->val; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - dev->ctl_mute = val; - tm6000_tvaudio_set_mute(dev, val); - return 0; - case V4L2_CID_AUDIO_VOLUME: - dev->ctl_volume = val; - tm6000_set_volume(dev, val); - return 0; - } - return -EINVAL; -} - -static const struct v4l2_ctrl_ops tm6000_radio_ctrl_ops = { - .s_ctrl = tm6000_radio_s_ctrl, -}; - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -ENOTTY; - if (0 != t->index) - return -EINVAL; - - strscpy(t->name, "Television", sizeof(t->name)); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - - t->audmode = dev->amode; - - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -ENOTTY; - if (0 != t->index) - return -EINVAL; - - if (t->audmode > V4L2_TUNER_MODE_STEREO) - dev->amode = V4L2_TUNER_MODE_STEREO; - else - dev->amode = t->audmode; - dprintk(dev, 3, "audio mode: %x\n", t->audmode); - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -ENOTTY; - if (f->tuner) - return -EINVAL; - - f->frequency = dev->freq; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f) -{ - struct tm6000_fh *fh = priv; - struct tm6000_core *dev = fh->dev; - - if (UNSET == dev->tuner_type) - return -ENOTTY; - if (f->tuner != 0) - return -EINVAL; - - dev->freq = f->frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); - - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - - memset(t, 0, sizeof(*t)); - strscpy(t->name, "Radio", sizeof(t->name)); - t->type = V4L2_TUNER_RADIO; - t->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - t->audmode = V4L2_TUNER_MODE_STEREO; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); - - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *t) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - return 0; -} - -/* ------------------------------------------------------------------ - File operations for the device - ------------------------------------------------------------------*/ - -static int __tm6000_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct tm6000_core *dev = video_drvdata(file); - struct tm6000_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int rc; - int radio = 0; - - dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n", - video_device_node_name(vdev)); - - switch (vdev->vfl_type) { - case VFL_TYPE_VIDEO: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - default: - return -EINVAL; - } - - /* If more than one user, mutex should be added */ - dev->users++; - - dprintk(dev, V4L2_DEBUG_OPEN, "open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[type], - dev->users); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) { - dev->users--; - return -ENOMEM; - } - - v4l2_fh_init(&fh->fh, vdev); - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - dev->radio = radio; - fh->type = type; - dev->fourcc = format[0].fourcc; - - fh->fmt = format_by_fourcc(dev->fourcc); - - tm6000_get_std_res(dev); - - fh->width = dev->width; - fh->height = dev->height; - - dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=%p, dev=%p, dev->vidq=%p\n", - fh, dev, &dev->vidq); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty queued=%d\n", - list_empty(&dev->vidq.queued)); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty active=%d\n", - list_empty(&dev->vidq.active)); - - /* initialize hardware on analog mode */ - rc = tm6000_init_analog_mode(dev); - if (rc < 0) { - v4l2_fh_exit(&fh->fh); - kfree(fh); - return rc; - } - - dev->mode = TM6000_MODE_ANALOG; - - if (!fh->radio) { - videobuf_queue_vmalloc_init(&fh->vb_vidq, &tm6000_video_qops, - NULL, &dev->slock, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct tm6000_buffer), fh, &dev->lock); - } else { - dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); - tm6000_set_audio_rinput(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); - tm6000_prepare_isoc(dev); - tm6000_start_thread(dev); - } - v4l2_fh_add(&fh->fh); - - return 0; -} - -static int tm6000_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - int res; - - mutex_lock(vdev->lock); - res = __tm6000_open(file); - mutex_unlock(vdev->lock); - return res; -} - -static ssize_t -tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - int res; - - if (!res_get(fh->dev, fh, true)) - return -EBUSY; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - res = videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0, - file->f_flags & O_NONBLOCK); - mutex_unlock(&dev->lock); - return res; - } - return 0; -} - -static __poll_t -__tm6000_poll(struct file *file, struct poll_table_struct *wait) -{ - __poll_t req_events = poll_requested_events(wait); - struct tm6000_fh *fh = file->private_data; - struct tm6000_buffer *buf; - __poll_t res = 0; - - if (v4l2_event_pending(&fh->fh)) - res = EPOLLPRI; - else if (req_events & EPOLLPRI) - poll_wait(file, &fh->fh.wait, wait); - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return res | EPOLLERR; - - if (!!is_res_streaming(fh->dev, fh)) - return res | EPOLLERR; - - if (!is_res_read(fh->dev, fh)) { - /* streaming capture */ - if (list_empty(&fh->vb_vidq.stream)) - return res | EPOLLERR; - buf = list_entry(fh->vb_vidq.stream.next, struct tm6000_buffer, vb.stream); - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return res | EPOLLIN | EPOLLRDNORM; - } else if (req_events & (EPOLLIN | EPOLLRDNORM)) { - /* read() capture */ - return res | videobuf_poll_stream(file, &fh->vb_vidq, wait); - } - return res; -} - -static __poll_t tm6000_poll(struct file *file, struct poll_table_struct *wait) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - __poll_t res; - - mutex_lock(&dev->lock); - res = __tm6000_poll(file, wait); - mutex_unlock(&dev->lock); - return res; -} - -static int tm6000_release(struct file *file) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - struct video_device *vdev = video_devdata(file); - - dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n", - video_device_node_name(vdev), dev->users); - - mutex_lock(&dev->lock); - dev->users--; - - res_free(dev, fh); - - if (!dev->users) { - tm6000_uninit_isoc(dev); - - /* Stop interrupt USB pipe */ - tm6000_ir_int_stop(dev); - - usb_reset_configuration(dev->udev); - - if (dev->int_in.endp) - usb_set_interface(dev->udev, - dev->isoc_in.bInterfaceNumber, 2); - else - usb_set_interface(dev->udev, - dev->isoc_in.bInterfaceNumber, 0); - - /* Start interrupt USB pipe */ - tm6000_ir_int_start(dev); - - if (!fh->radio) - videobuf_mmap_free(&fh->vb_vidq); - } - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - kfree(fh); - mutex_unlock(&dev->lock); - - return 0; -} - -static int tm6000_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct tm6000_fh *fh = file->private_data; - struct tm6000_core *dev = fh->dev; - int res; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - res = videobuf_mmap_mapper(&fh->vb_vidq, vma); - mutex_unlock(&dev->lock); - return res; -} - -static const struct v4l2_file_operations tm6000_fops = { - .owner = THIS_MODULE, - .open = tm6000_open, - .release = tm6000_release, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .read = tm6000_read, - .poll = tm6000_poll, - .mmap = tm6000_mmap, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_s_std = vidioc_s_std, - .vidioc_g_std = vidioc_g_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static struct video_device tm6000_template = { - .name = "tm6000", - .fops = &tm6000_fops, - .ioctl_ops = &video_ioctl_ops, - .release = video_device_release_empty, - .tvnorms = TM6000_STD, -}; - -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = tm6000_open, - .poll = v4l2_ctrl_poll, - .release = tm6000_release, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static struct video_device tm6000_radio_template = { - .name = "tm6000", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/* ----------------------------------------------------------------- - * Initialization and module stuff - * ------------------------------------------------------------------ - */ - -static void vdev_init(struct tm6000_core *dev, - struct video_device *vfd, - const struct video_device - *template, const char *type_name) -{ - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release_empty; - vfd->lock = &dev->lock; - - snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); - - video_set_drvdata(vfd, dev); -} - -int tm6000_v4l2_register(struct tm6000_core *dev) -{ - int ret = 0; - - v4l2_ctrl_handler_init(&dev->ctrl_handler, 6); - v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 2); - v4l2_ctrl_new_std(&dev->radio_ctrl_handler, &tm6000_radio_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - v4l2_ctrl_new_std(&dev->radio_ctrl_handler, &tm6000_radio_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, -15, 15, 1, 0); - v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 54); - v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 119); - v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 112); - v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - v4l2_ctrl_add_handler(&dev->ctrl_handler, - &dev->radio_ctrl_handler, NULL, false); - - if (dev->radio_ctrl_handler.error) - ret = dev->radio_ctrl_handler.error; - if (!ret && dev->ctrl_handler.error) - ret = dev->ctrl_handler.error; - if (ret) - goto free_ctrl; - - vdev_init(dev, &dev->vfd, &tm6000_template, "video"); - - dev->vfd.ctrl_handler = &dev->ctrl_handler; - dev->vfd.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - if (dev->tuner_type != TUNER_ABSENT) - dev->vfd.device_caps |= V4L2_CAP_TUNER; - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - - ret = video_register_device(&dev->vfd, VFL_TYPE_VIDEO, video_nr); - - if (ret < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - goto free_ctrl; - } - - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(&dev->vfd)); - - if (dev->caps.has_radio) { - vdev_init(dev, &dev->radio_dev, &tm6000_radio_template, - "radio"); - dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler; - dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, - radio_nr); - if (ret < 0) { - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - goto unreg_video; - } - - printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(&dev->radio_dev)); - } - - printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); - return ret; - -unreg_video: - video_unregister_device(&dev->vfd); -free_ctrl: - v4l2_ctrl_handler_free(&dev->ctrl_handler); - v4l2_ctrl_handler_free(&dev->radio_ctrl_handler); - return ret; -} - -int tm6000_v4l2_unregister(struct tm6000_core *dev) -{ - video_unregister_device(&dev->vfd); - - /* if URB buffers are still allocated free them now */ - tm6000_free_urb_buffers(dev); - - video_unregister_device(&dev->radio_dev); - return 0; -} - -int tm6000_v4l2_exit(void) -{ - return 0; -} - -module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "Allow changing video device number"); - -module_param_named(debug, tm6000_debug, int, 0444); -MODULE_PARM_DESC(debug, "activates debug info"); - -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - -module_param(keep_urb, bool, 0); -MODULE_PARM_DESC(keep_urb, "Keep urb buffers allocated even when the device is closed by the user"); diff --git a/drivers/staging/media/deprecated/tm6000/tm6000.h b/drivers/staging/media/deprecated/tm6000/tm6000.h deleted file mode 100644 index c08c95312739..000000000000 --- a/drivers/staging/media/deprecated/tm6000/tm6000.h +++ /dev/null @@ -1,396 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices - * - * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> - * - * Copyright (c) 2007 Michel Ludwig <michel.ludwig@gmail.com> - * - DVB-T support - */ - -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/videobuf-vmalloc.h> -#include "tm6000-usb-isoc.h" -#include <linux/i2c.h> -#include <linux/mutex.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-fh.h> - -#include <linux/dvb/frontend.h> -#include <media/dvb_demux.h> -#include <media/dvb_frontend.h> -#include <media/dmxdev.h> - -/* Inputs */ -enum tm6000_itype { - TM6000_INPUT_TV = 1, - TM6000_INPUT_COMPOSITE1, - TM6000_INPUT_COMPOSITE2, - TM6000_INPUT_SVIDEO, - TM6000_INPUT_DVB, - TM6000_INPUT_RADIO, -}; - -enum tm6000_mux { - TM6000_VMUX_VIDEO_A = 1, - TM6000_VMUX_VIDEO_B, - TM6000_VMUX_VIDEO_AB, - TM6000_AMUX_ADC1, - TM6000_AMUX_ADC2, - TM6000_AMUX_SIF1, - TM6000_AMUX_SIF2, - TM6000_AMUX_I2S, -}; - -enum tm6000_devtype { - TM6000 = 0, - TM5600, - TM6010, -}; - -struct tm6000_input { - enum tm6000_itype type; - enum tm6000_mux vmux; - enum tm6000_mux amux; - unsigned int v_gpio; - unsigned int a_gpio; -}; - -/* ------------------------------------------------------------------ - * Basic structures - * ------------------------------------------------------------------ - */ - -struct tm6000_fmt { - u32 fourcc; /* v4l2 format id */ - int depth; -}; - -/* buffer for one video frame */ -struct tm6000_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - struct tm6000_fmt *fmt; -}; - -struct tm6000_dmaqueue { - struct list_head active; - struct list_head queued; - - /* thread for generating video stream*/ - struct task_struct *kthread; - wait_queue_head_t wq; - /* Counters to control fps rate */ - int frame; - int ini_jiffies; -}; - -/* device states */ -enum tm6000_core_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -/* io methods */ -enum tm6000_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum tm6000_mode { - TM6000_MODE_UNKNOWN = 0, - TM6000_MODE_ANALOG, - TM6000_MODE_DIGITAL, -}; - -struct tm6000_gpio { - int tuner_reset; - int tuner_on; - int demod_reset; - int demod_on; - int power_led; - int dvb_led; - int ir; -}; - -struct tm6000_capabilities { - unsigned int has_tuner:1; - unsigned int has_tda9874:1; - unsigned int has_dvb:1; - unsigned int has_zl10353:1; - unsigned int has_eeprom:1; - unsigned int has_remote:1; - unsigned int has_radio:1; -}; - -struct tm6000_dvb { - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dvb_frontend *frontend; - struct dmxdev dmxdev; - unsigned int streams; - struct urb *bulk_urb; - struct mutex mutex; -}; - -struct snd_tm6000_card { - struct snd_card *card; - spinlock_t reg_lock; - struct tm6000_core *core; - struct snd_pcm_substream *substream; - - /* temporary data for buffer fill processing */ - unsigned buf_pos; - unsigned period_pos; -}; - -struct tm6000_endpoint { - struct usb_host_endpoint *endp; - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - unsigned maxsize; -}; - -#define TM6000_QUIRK_NO_USB_DELAY (1 << 0) - -struct tm6000_core { - /* generic device properties */ - char name[30]; /* name (including minor) of the device */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ - enum tm6000_devtype dev_type; /* type of device */ - unsigned char eedata[256]; /* Eeprom data */ - unsigned eedata_size; /* Size of the eeprom info */ - - v4l2_std_id norm; /* Current norm */ - int width, height; /* Selected resolution */ - - enum tm6000_core_state state; - - /* Device Capabilities*/ - struct tm6000_capabilities caps; - - /* Used to load alsa/dvb */ - struct work_struct request_module_wk; - - /* Tuner configuration */ - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - - struct tm6000_gpio gpio; - - char *ir_codes; - - __u8 radio; - - /* Demodulator configuration */ - int demod_addr; /* demodulator address */ - - int audio_bitrate; - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - - - /* extension */ - struct list_head devlist; - - /* video for linux */ - int users; - - /* various device info */ - struct tm6000_fh *resources; /* Points to fh that is streaming */ - bool is_res_read; - - struct video_device vfd; - struct video_device radio_dev; - struct tm6000_dmaqueue vidq; - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl_handler radio_ctrl_handler; - - int input; - struct tm6000_input vinput[3]; /* video input */ - struct tm6000_input rinput; /* radio input */ - - int freq; - unsigned int fourcc; - - enum tm6000_mode mode; - - int ctl_mute; /* audio */ - int ctl_volume; - int amode; - - /* DVB-T support */ - struct tm6000_dvb *dvb; - - /* audio support */ - struct snd_tm6000_card *adev; - struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ - atomic_t stream_started; /* stream should be running if true */ - - struct tm6000_IR *ir; - - /* locks */ - struct mutex lock; - struct mutex usb_lock; - - /* usb transfer */ - struct usb_device *udev; /* the usb device */ - - struct tm6000_endpoint bulk_in, bulk_out, isoc_in, isoc_out; - struct tm6000_endpoint int_in, int_out; - - /* scaler!=0 if scaler is active*/ - int scaler; - - /* Isoc control struct */ - struct usb_isoc_ctl isoc_ctl; - - spinlock_t slock; - - /* urb dma buffers */ - char **urb_buffer; - dma_addr_t *urb_dma; - unsigned int urb_size; - - unsigned long quirks; -}; - -enum tm6000_ops_type { - TM6000_AUDIO = 0x10, - TM6000_DVB = 0x20, -}; - -struct tm6000_ops { - struct list_head next; - char *name; - enum tm6000_ops_type type; - int (*init)(struct tm6000_core *); - int (*fini)(struct tm6000_core *); - int (*fillbuf)(struct tm6000_core *, char *buf, int size); -}; - -struct tm6000_fh { - struct v4l2_fh fh; - struct tm6000_core *dev; - unsigned int radio; - - /* video capture */ - struct tm6000_fmt *fmt; - unsigned int width, height; - struct videobuf_queue vb_vidq; - - enum v4l2_buf_type type; -}; - -#define TM6000_STD (V4L2_STD_PAL|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc| \ - V4L2_STD_PAL_M|V4L2_STD_PAL_60|V4L2_STD_NTSC_M| \ - V4L2_STD_NTSC_M_JP|V4L2_STD_SECAM) - -/* In tm6000-cards.c */ - -int tm6000_tuner_callback(void *ptr, int component, int command, int arg); -int tm6000_xc5000_callback(void *ptr, int component, int command, int arg); -int tm6000_cards_setup(struct tm6000_core *dev); -void tm6000_flash_led(struct tm6000_core *dev, u8 state); - -/* In tm6000-core.c */ - -int tm6000_read_write_usb(struct tm6000_core *dev, u8 reqtype, u8 req, - u16 value, u16 index, u8 *buf, u16 len); -int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); -int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, - u16 index, u16 mask); -int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); -int tm6000_init(struct tm6000_core *dev); -int tm6000_reset(struct tm6000_core *dev); - -int tm6000_init_analog_mode(struct tm6000_core *dev); -int tm6000_init_digital_mode(struct tm6000_core *dev); -int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate); -int tm6000_set_audio_rinput(struct tm6000_core *dev); -int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute); -void tm6000_set_volume(struct tm6000_core *dev, int vol); - -int tm6000_v4l2_register(struct tm6000_core *dev); -int tm6000_v4l2_unregister(struct tm6000_core *dev); -int tm6000_v4l2_exit(void); -void tm6000_set_fourcc_format(struct tm6000_core *dev); - -void tm6000_remove_from_devlist(struct tm6000_core *dev); -void tm6000_add_into_devlist(struct tm6000_core *dev); -int tm6000_register_extension(struct tm6000_ops *ops); -void tm6000_unregister_extension(struct tm6000_ops *ops); -void tm6000_init_extension(struct tm6000_core *dev); -void tm6000_close_extension(struct tm6000_core *dev); -int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, - char *buf, int size); - - -/* In tm6000-stds.c */ -void tm6000_get_std_res(struct tm6000_core *dev); -int tm6000_set_standard(struct tm6000_core *dev); - -/* In tm6000-i2c.c */ -int tm6000_i2c_register(struct tm6000_core *dev); -int tm6000_i2c_unregister(struct tm6000_core *dev); - -/* In tm6000-queue.c */ - -int tm6000_v4l2_mmap(struct file *filp, struct vm_area_struct *vma); - -int tm6000_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i); -int tm6000_vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type i); -int tm6000_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb); -int tm6000_vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b); -int tm6000_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b); -int tm6000_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b); -ssize_t tm6000_v4l2_read(struct file *filp, char __user * buf, size_t count, - loff_t *f_pos); -unsigned int tm6000_v4l2_poll(struct file *file, - struct poll_table_struct *wait); -int tm6000_queue_init(struct tm6000_core *dev); - -/* In tm6000-alsa.c */ -/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/ - -/* In tm6000-input.c */ -int tm6000_ir_init(struct tm6000_core *dev); -int tm6000_ir_fini(struct tm6000_core *dev); -void tm6000_ir_wait(struct tm6000_core *dev, u8 state); -int tm6000_ir_int_start(struct tm6000_core *dev); -void tm6000_ir_int_stop(struct tm6000_core *dev); - -/* Debug stuff */ - -extern int tm6000_debug; - -#define dprintk(dev, level, fmt, arg...) do {\ - if (tm6000_debug & level) \ - printk(KERN_INFO "(%lu) %s %s :"fmt, jiffies, \ - dev->name, __func__ , ##arg); } while (0) - -#define V4L2_DEBUG_REG 0x0004 -#define V4L2_DEBUG_I2C 0x0008 -#define V4L2_DEBUG_QUEUE 0x0010 -#define V4L2_DEBUG_ISOC 0x0020 -#define V4L2_DEBUG_RES_LOCK 0x0040 /* Resource locking */ -#define V4L2_DEBUG_OPEN 0x0080 /* video open/close debug */ - -#define tm6000_err(fmt, arg...) do {\ - printk(KERN_ERR "tm6000 %s :"fmt, \ - __func__ , ##arg); } while (0) diff --git a/drivers/staging/media/deprecated/zr364xx/Kconfig b/drivers/staging/media/deprecated/zr364xx/Kconfig deleted file mode 100644 index ea29c9d8dca2..000000000000 --- a/drivers/staging/media/deprecated/zr364xx/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config USB_ZR364XX - tristate "USB ZR364XX Camera support (DEPRECATED)" - depends on USB && VIDEO_DEV - select VIDEOBUF_GEN - select VIDEOBUF_VMALLOC - help - Say Y here if you want to connect this type of camera to your - computer's USB port. - See <file:Documentation/admin-guide/media/zr364xx.rst> for more info - and list of supported cameras. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here: the - module will be called zr364xx. - diff --git a/drivers/staging/media/deprecated/zr364xx/Makefile b/drivers/staging/media/deprecated/zr364xx/Makefile deleted file mode 100644 index edab017d499c..000000000000 --- a/drivers/staging/media/deprecated/zr364xx/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_USB_ZR364XX) += zr364xx.o - diff --git a/drivers/staging/media/deprecated/zr364xx/TODO b/drivers/staging/media/deprecated/zr364xx/TODO deleted file mode 100644 index ecb30a429689..000000000000 --- a/drivers/staging/media/deprecated/zr364xx/TODO +++ /dev/null @@ -1,7 +0,0 @@ -This is one of the few drivers still not using the vb2 -framework, so this driver is now deprecated with the intent of -removing it altogether by the beginning of 2023. - -In order to keep this driver it has to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/zr364xx/zr364xx.c b/drivers/staging/media/deprecated/zr364xx/zr364xx.c deleted file mode 100644 index 538a330046ec..000000000000 --- a/drivers/staging/media/deprecated/zr364xx/zr364xx.c +++ /dev/null @@ -1,1635 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Zoran 364xx based USB webcam module version 0.73 - * - * Allows you to use your USB webcam with V4L2 applications - * This is still in heavy development ! - * - * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com> - * http://royale.zerezo.com/zr364xx/ - * - * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers - * V4L2 version inspired by meye.c driver - * - * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers. - */ - - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/usb.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> -#include <linux/highmem.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-fh.h> -#include <media/v4l2-event.h> -#include <media/videobuf-vmalloc.h> - - -/* Version Information */ -#define DRIVER_VERSION "0.7.4" -#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" -#define DRIVER_DESC "Zoran 364xx" - - -/* Camera */ -#define FRAMES 1 -#define MAX_FRAME_SIZE 200000 -#define BUFFER_SIZE 0x1000 -#define CTRL_TIMEOUT 500 - -#define ZR364XX_DEF_BUFS 4 -#define ZR364XX_READ_IDLE 0 -#define ZR364XX_READ_FRAME 1 - -/* Debug macro */ -#define DBG(fmt, args...) \ - do { \ - if (debug) { \ - printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \ - } \ - } while (0) - -/*#define FULL_DEBUG 1*/ -#ifdef FULL_DEBUG -#define _DBG DBG -#else -#define _DBG(fmt, args...) -#endif - -/* Init methods, need to find nicer names for these - * the exact names of the chipsets would be the best if someone finds it */ -#define METHOD0 0 -#define METHOD1 1 -#define METHOD2 2 -#define METHOD3 3 - - -/* Module parameters */ -static int debug; -static int mode; - - -/* Module parameters interface */ -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level"); -module_param(mode, int, 0644); -MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480"); - - -/* Devices supported by this driver - * .driver_info contains the init method used by the camera */ -static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 }, - {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 }, - {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 }, - {USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 }, - {USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 }, - {USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 }, - {USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 }, - {USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 }, - {USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 }, - {USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 }, - {USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 }, - {USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 }, - {USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 }, - {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 }, - {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, - {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, - {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 }, - {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 }, - {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 }, - {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD3 }, - {USB_DEVICE(0x06d6, 0x003d), .driver_info = METHOD0 }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -/* frame structure */ -struct zr364xx_framei { - unsigned long ulState; /* ulState:ZR364XX_READ_IDLE, - ZR364XX_READ_FRAME */ - void *lpvbits; /* image data */ - unsigned long cur_size; /* current data copied to it */ -}; - -/* image buffer structure */ -struct zr364xx_bufferi { - unsigned long dwFrames; /* number of frames in buffer */ - struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */ -}; - -struct zr364xx_dmaqueue { - struct list_head active; - struct zr364xx_camera *cam; -}; - -struct zr364xx_pipeinfo { - u32 transfer_size; - u8 *transfer_buffer; - u32 state; - void *stream_urb; - void *cam; /* back pointer to zr364xx_camera struct */ - u32 err_count; - u32 idx; -}; - -struct zr364xx_fmt { - u32 fourcc; - int depth; -}; - -/* image formats. */ -static const struct zr364xx_fmt formats[] = { - { - .fourcc = V4L2_PIX_FMT_JPEG, - .depth = 24 - } -}; - -/* Camera stuff */ -struct zr364xx_camera { - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface;/* the interface for this device */ - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler ctrl_handler; - struct video_device vdev; /* v4l video device */ - struct v4l2_fh *owner; /* owns the streaming */ - int nb; - struct zr364xx_bufferi buffer; - int skip; - int width; - int height; - int method; - struct mutex lock; - - spinlock_t slock; - struct zr364xx_dmaqueue vidq; - int last_frame; - int cur_frame; - unsigned long frame_count; - int b_acquire; - struct zr364xx_pipeinfo pipe[1]; - - u8 read_endpoint; - - const struct zr364xx_fmt *fmt; - struct videobuf_queue vb_vidq; - bool was_streaming; -}; - -/* buffer for one video frame */ -struct zr364xx_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - const struct zr364xx_fmt *fmt; -}; - -/* function used to send initialisation commands to the camera */ -static int send_control_msg(struct usb_device *udev, u8 request, u16 value, - u16 index, unsigned char *cp, u16 size) -{ - int status; - - unsigned char *transfer_buffer = kmemdup(cp, size, GFP_KERNEL); - if (!transfer_buffer) - return -ENOMEM; - - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, value, index, - transfer_buffer, size, CTRL_TIMEOUT); - - kfree(transfer_buffer); - return status; -} - - -/* Control messages sent to the camera to initialize it - * and launch the capture */ -typedef struct { - unsigned int value; - unsigned int size; - unsigned char *bytes; -} message; - -/* method 0 */ -static unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 }; -static unsigned char m0d3[] = { 0, 0 }; -static message m0[] = { - {0x1f30, 0, NULL}, - {0xd000, 0, NULL}, - {0x3370, sizeof(m0d1), m0d1}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2610, sizeof(m0d2), m0d2}, - {0xe107, 0, NULL}, - {0x2502, 0, NULL}, - {0x1f70, 0, NULL}, - {0xd000, 0, NULL}, - {0x9a01, sizeof(m0d3), m0d3}, - {-1, -1, NULL} -}; - -/* method 1 */ -static unsigned char m1d1[] = { 0xff, 0xff }; -static unsigned char m1d2[] = { 0x00, 0x00 }; -static message m1[] = { - {0x1f30, 0, NULL}, - {0xd000, 0, NULL}, - {0xf000, 0, NULL}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2650, 0, NULL}, - {0xe107, 0, NULL}, - {0x2502, sizeof(m1d1), m1d1}, - {0x1f70, 0, NULL}, - {0xd000, 0, NULL}, - {0xd000, 0, NULL}, - {0xd000, 0, NULL}, - {0x9a01, sizeof(m1d2), m1d2}, - {-1, -1, NULL} -}; - -/* method 2 */ -static unsigned char m2d1[] = { 0xff, 0xff }; -static message m2[] = { - {0x1f30, 0, NULL}, - {0xf000, 0, NULL}, - {0x2000, 0, NULL}, - {0x2f0f, 0, NULL}, - {0x2650, 0, NULL}, - {0xe107, 0, NULL}, - {0x2502, sizeof(m2d1), m2d1}, - {0x1f70, 0, NULL}, - {-1, -1, NULL} -}; - -/* init table */ -static message *init[4] = { m0, m1, m2, m2 }; - - -/* JPEG static data in header (Huffman table, etc) */ -static unsigned char header1[] = { - 0xFF, 0xD8, - /* - 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F', - 0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88, - */ - 0xFF, 0xDB, 0x00, 0x84 -}; -static unsigned char header2[] = { - 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, - 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, - 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, - 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, - 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, - 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, - 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, - 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, - 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, - 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, - 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, - 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, - 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, - 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, - 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, - 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, - 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, - 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, - 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, - 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, - 0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, - 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, - 0x00, 0x3F, 0x00 -}; -static unsigned char header3; - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ - -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct zr364xx_camera *cam = vq->priv_data; - - *size = cam->width * cam->height * (cam->fmt->depth >> 3); - - if (*count == 0) - *count = ZR364XX_DEF_BUFS; - - if (*size * *count > ZR364XX_DEF_BUFS * 1024 * 1024) - *count = (ZR364XX_DEF_BUFS * 1024 * 1024) / *size; - - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf) -{ - _DBG("%s\n", __func__); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct zr364xx_camera *cam = vq->priv_data; - struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, - vb); - int rc; - - DBG("%s, field=%d\n", __func__, field); - if (!cam->fmt) - return -EINVAL; - - buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3); - - if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) { - DBG("invalid buffer prepare\n"); - return -EINVAL; - } - - buf->fmt = cam->fmt; - buf->vb.width = cam->width; - buf->vb.height = cam->height; - buf->vb.field = field; - - if (buf->vb.state == VIDEOBUF_NEEDS_INIT) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; -fail: - free_buffer(vq, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, - vb); - struct zr364xx_camera *cam = vq->priv_data; - - _DBG("%s\n", __func__); - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &cam->vidq.active); -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, - vb); - - _DBG("%s\n", __func__); - free_buffer(vq, buf); -} - -static const struct videobuf_queue_ops zr364xx_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/********************/ -/* V4L2 integration */ -/********************/ -static int zr364xx_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type); - -static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count, - loff_t * ppos) -{ - struct zr364xx_camera *cam = video_drvdata(file); - int err = 0; - - _DBG("%s\n", __func__); - - if (!buf) - return -EINVAL; - - if (!count) - return -EINVAL; - - if (mutex_lock_interruptible(&cam->lock)) - return -ERESTARTSYS; - - err = zr364xx_vidioc_streamon(file, file->private_data, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (err == 0) { - DBG("%s: reading %d bytes at pos %d.\n", __func__, - (int) count, (int) *ppos); - - /* NoMan Sux ! */ - err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos, - file->f_flags & O_NONBLOCK); - } - mutex_unlock(&cam->lock); - return err; -} - -/* video buffer vmalloc implementation based partly on VIVI driver which is - * Copyright (c) 2006 by - * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> - * Ted Walther <ted--a.t--enumera.com> - * John Sokol <sokol--a.t--videotechnology.com> - * http://v4l.videotechnology.com/ - * - */ -static void zr364xx_fillbuff(struct zr364xx_camera *cam, - struct zr364xx_buffer *buf, - int jpgsize) -{ - int pos = 0; - const char *tmpbuf; - char *vbuf = videobuf_to_vmalloc(&buf->vb); - unsigned long last_frame; - - if (!vbuf) - return; - - last_frame = cam->last_frame; - if (last_frame != -1) { - tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits; - switch (buf->fmt->fourcc) { - case V4L2_PIX_FMT_JPEG: - buf->vb.size = jpgsize; - memcpy(vbuf, tmpbuf, buf->vb.size); - break; - default: - printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n"); - } - cam->last_frame = -1; - } else { - printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n"); - return; - } - DBG("%s: Buffer %p size= %d\n", __func__, vbuf, pos); - /* tell v4l buffer was filled */ - - buf->vb.field_count = cam->frame_count * 2; - buf->vb.ts = ktime_get_ns(); - buf->vb.state = VIDEOBUF_DONE; -} - -static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize) -{ - struct zr364xx_dmaqueue *dma_q = &cam->vidq; - struct zr364xx_buffer *buf; - unsigned long flags = 0; - int rc = 0; - - DBG("wakeup: %p\n", &dma_q); - spin_lock_irqsave(&cam->slock, flags); - - if (list_empty(&dma_q->active)) { - DBG("No active queue to serve\n"); - rc = -1; - goto unlock; - } - buf = list_entry(dma_q->active.next, - struct zr364xx_buffer, vb.queue); - - if (!waitqueue_active(&buf->vb.done)) { - /* no one active */ - rc = -1; - goto unlock; - } - list_del(&buf->vb.queue); - buf->vb.ts = ktime_get_ns(); - DBG("[%p/%d] wakeup\n", buf, buf->vb.i); - zr364xx_fillbuff(cam, buf, jpgsize); - wake_up(&buf->vb.done); - DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i); -unlock: - spin_unlock_irqrestore(&cam->slock, flags); - return rc; -} - -/* this function moves the usb stream read pipe data - * into the system buffers. - * returns 0 on success, EAGAIN if more data to process (call this - * function again). - */ -static int zr364xx_read_video_callback(struct zr364xx_camera *cam, - struct zr364xx_pipeinfo *pipe_info, - struct urb *purb) -{ - unsigned char *pdest; - unsigned char *psrc; - s32 idx = cam->cur_frame; - struct zr364xx_framei *frm = &cam->buffer.frame[idx]; - int i = 0; - unsigned char *ptr = NULL; - - _DBG("buffer to user\n"); - - /* swap bytes if camera needs it */ - if (cam->method == METHOD0) { - u16 *buf = (u16 *)pipe_info->transfer_buffer; - for (i = 0; i < purb->actual_length/2; i++) - swab16s(buf + i); - } - - /* search done. now find out if should be acquiring */ - if (!cam->b_acquire) { - /* we found a frame, but this channel is turned off */ - frm->ulState = ZR364XX_READ_IDLE; - return -EINVAL; - } - - psrc = (u8 *)pipe_info->transfer_buffer; - ptr = pdest = frm->lpvbits; - - if (frm->ulState == ZR364XX_READ_IDLE) { - if (purb->actual_length < 128) { - /* header incomplete */ - dev_info(&cam->udev->dev, - "%s: buffer (%d bytes) too small to hold jpeg header. Discarding.\n", - __func__, purb->actual_length); - return -EINVAL; - } - - frm->ulState = ZR364XX_READ_FRAME; - frm->cur_size = 0; - - _DBG("jpeg header, "); - memcpy(ptr, header1, sizeof(header1)); - ptr += sizeof(header1); - header3 = 0; - memcpy(ptr, &header3, 1); - ptr++; - memcpy(ptr, psrc, 64); - ptr += 64; - header3 = 1; - memcpy(ptr, &header3, 1); - ptr++; - memcpy(ptr, psrc + 64, 64); - ptr += 64; - memcpy(ptr, header2, sizeof(header2)); - ptr += sizeof(header2); - memcpy(ptr, psrc + 128, - purb->actual_length - 128); - ptr += purb->actual_length - 128; - _DBG("header : %d %d %d %d %d %d %d %d %d\n", - psrc[0], psrc[1], psrc[2], - psrc[3], psrc[4], psrc[5], - psrc[6], psrc[7], psrc[8]); - frm->cur_size = ptr - pdest; - } else { - if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) { - dev_info(&cam->udev->dev, - "%s: buffer (%d bytes) too small to hold frame data. Discarding frame data.\n", - __func__, MAX_FRAME_SIZE); - } else { - pdest += frm->cur_size; - memcpy(pdest, psrc, purb->actual_length); - frm->cur_size += purb->actual_length; - } - } - /*_DBG("cur_size %lu urb size %d\n", frm->cur_size, - purb->actual_length);*/ - - if (purb->actual_length < pipe_info->transfer_size) { - _DBG("****************Buffer[%d]full*************\n", idx); - cam->last_frame = cam->cur_frame; - cam->cur_frame++; - /* end of system frame ring buffer, start at zero */ - if (cam->cur_frame == cam->buffer.dwFrames) - cam->cur_frame = 0; - - /* frame ready */ - /* go back to find the JPEG EOI marker */ - ptr = pdest = frm->lpvbits; - ptr += frm->cur_size - 2; - while (ptr > pdest) { - if (*ptr == 0xFF && *(ptr + 1) == 0xD9 - && *(ptr + 2) == 0xFF) - break; - ptr--; - } - if (ptr == pdest) - DBG("No EOI marker\n"); - - /* Sometimes there is junk data in the middle of the picture, - * we want to skip this bogus frames */ - while (ptr > pdest) { - if (*ptr == 0xFF && *(ptr + 1) == 0xFF - && *(ptr + 2) == 0xFF) - break; - ptr--; - } - if (ptr != pdest) { - DBG("Bogus frame ? %d\n", ++(cam->nb)); - } else if (cam->b_acquire) { - /* we skip the 2 first frames which are usually buggy */ - if (cam->skip) - cam->skip--; - else { - _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n", - frm->cur_size, - pdest[0], pdest[1], pdest[2], pdest[3], - pdest[4], pdest[5], pdest[6], pdest[7]); - - zr364xx_got_frame(cam, frm->cur_size); - } - } - cam->frame_count++; - frm->ulState = ZR364XX_READ_IDLE; - frm->cur_size = 0; - } - /* done successfully */ - return 0; -} - -static int zr364xx_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct zr364xx_camera *cam = video_drvdata(file); - - strscpy(cap->driver, DRIVER_DESC, sizeof(cap->driver)); - if (cam->udev->product) - strscpy(cap->card, cam->udev->product, sizeof(cap->card)); - strscpy(cap->bus_info, dev_name(&cam->udev->dev), - sizeof(cap->bus_info)); - return 0; -} - -static int zr364xx_vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strscpy(i->name, DRIVER_DESC " Camera", sizeof(i->name)); - i->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - -static int zr364xx_vidioc_g_input(struct file *file, void *priv, - unsigned int *i) -{ - *i = 0; - return 0; -} - -static int zr364xx_vidioc_s_input(struct file *file, void *priv, - unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int zr364xx_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct zr364xx_camera *cam = - container_of(ctrl->handler, struct zr364xx_camera, ctrl_handler); - int temp; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - /* hardware brightness */ - send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0); - temp = (0x60 << 8) + 127 - ctrl->val; - send_control_msg(cam->udev, 1, temp, 0, NULL, 0); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file, - void *priv, struct v4l2_fmtdesc *f) -{ - if (f->index > 0) - return -EINVAL; - f->pixelformat = formats[0].fourcc; - return 0; -} - -static char *decode_fourcc(__u32 pixelformat, char *buf) -{ - buf[0] = pixelformat & 0xff; - buf[1] = (pixelformat >> 8) & 0xff; - buf[2] = (pixelformat >> 16) & 0xff; - buf[3] = (pixelformat >> 24) & 0xff; - buf[4] = '\0'; - return buf; -} - -static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct zr364xx_camera *cam = video_drvdata(file); - char pixelformat_name[5]; - - if (!cam) - return -ENODEV; - - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) { - DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__, - decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name)); - return -EINVAL; - } - - if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) && - !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - } - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, - decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), - f->fmt.pix.field); - return 0; -} - -static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct zr364xx_camera *cam; - - if (!file) - return -ENODEV; - cam = video_drvdata(file); - - f->fmt.pix.pixelformat = formats[0].fourcc; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = cam->width; - f->fmt.pix.height = cam->height; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - return 0; -} - -static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct zr364xx_camera *cam = video_drvdata(file); - struct videobuf_queue *q = &cam->vb_vidq; - char pixelformat_name[5]; - int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f); - int i; - - if (ret < 0) - return ret; - - mutex_lock(&q->vb_lock); - - if (videobuf_queue_is_busy(&cam->vb_vidq)) { - DBG("%s queue busy\n", __func__); - ret = -EBUSY; - goto out; - } - - if (cam->owner) { - DBG("%s can't change format after started\n", __func__); - ret = -EBUSY; - goto out; - } - - cam->width = f->fmt.pix.width; - cam->height = f->fmt.pix.height; - DBG("%s: %dx%d mode selected\n", __func__, - cam->width, cam->height); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - cam->vb_vidq.field = f->fmt.pix.field; - - if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120) - mode = 1; - else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480) - mode = 2; - else - mode = 0; - - m0d1[0] = mode; - m1[2].value = 0xf000 + mode; - m2[1].value = 0xf000 + mode; - - /* special case for METHOD3, the modes are different */ - if (cam->method == METHOD3) { - switch (mode) { - case 1: - m2[1].value = 0xf000 + 4; - break; - case 2: - m2[1].value = 0xf000 + 0; - break; - default: - m2[1].value = 0xf000 + 1; - break; - } - } - - header2[437] = cam->height / 256; - header2[438] = cam->height % 256; - header2[439] = cam->width / 256; - header2[440] = cam->width % 256; - - for (i = 0; init[cam->method][i].size != -1; i++) { - ret = - send_control_msg(cam->udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (ret < 0) { - dev_err(&cam->udev->dev, - "error during resolution change sequence: %d\n", i); - goto out; - } - } - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - cam->skip = 2; - ret = 0; - -out: - mutex_unlock(&q->vb_lock); - - DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, - decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), - f->fmt.pix.field); - return ret; -} - -static int zr364xx_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct zr364xx_camera *cam = video_drvdata(file); - - if (cam->owner && cam->owner != priv) - return -EBUSY; - return videobuf_reqbufs(&cam->vb_vidq, p); -} - -static int zr364xx_vidioc_querybuf(struct file *file, - void *priv, - struct v4l2_buffer *p) -{ - int rc; - struct zr364xx_camera *cam = video_drvdata(file); - rc = videobuf_querybuf(&cam->vb_vidq, p); - return rc; -} - -static int zr364xx_vidioc_qbuf(struct file *file, - void *priv, - struct v4l2_buffer *p) -{ - int rc; - struct zr364xx_camera *cam = video_drvdata(file); - _DBG("%s\n", __func__); - if (cam->owner && cam->owner != priv) - return -EBUSY; - rc = videobuf_qbuf(&cam->vb_vidq, p); - return rc; -} - -static int zr364xx_vidioc_dqbuf(struct file *file, - void *priv, - struct v4l2_buffer *p) -{ - int rc; - struct zr364xx_camera *cam = video_drvdata(file); - _DBG("%s\n", __func__); - if (cam->owner && cam->owner != priv) - return -EBUSY; - rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK); - return rc; -} - -static void read_pipe_completion(struct urb *purb) -{ - struct zr364xx_pipeinfo *pipe_info; - struct zr364xx_camera *cam; - int pipe; - - pipe_info = purb->context; - _DBG("%s %p, status %d\n", __func__, purb, purb->status); - if (!pipe_info) { - printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); - return; - } - - cam = pipe_info->cam; - if (!cam) { - printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); - return; - } - - /* if shutting down, do not resubmit, exit immediately */ - if (purb->status == -ESHUTDOWN) { - DBG("%s, err shutdown\n", __func__); - pipe_info->err_count++; - return; - } - - if (pipe_info->state == 0) { - DBG("exiting USB pipe\n"); - return; - } - - if (purb->actual_length > pipe_info->transfer_size) { - dev_err(&cam->udev->dev, "wrong number of bytes\n"); - return; - } - - if (purb->status == 0) - zr364xx_read_video_callback(cam, pipe_info, purb); - else { - pipe_info->err_count++; - DBG("%s: failed URB %d\n", __func__, purb->status); - } - - pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint); - - /* reuse urb */ - usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev, - pipe, - pipe_info->transfer_buffer, - pipe_info->transfer_size, - read_pipe_completion, pipe_info); - - if (pipe_info->state != 0) { - purb->status = usb_submit_urb(pipe_info->stream_urb, - GFP_ATOMIC); - - if (purb->status) - dev_err(&cam->udev->dev, - "error submitting urb (error=%i)\n", - purb->status); - } else - DBG("read pipe complete state 0\n"); -} - -static int zr364xx_start_readpipe(struct zr364xx_camera *cam) -{ - int pipe; - int retval; - struct zr364xx_pipeinfo *pipe_info = cam->pipe; - pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint); - DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint); - - pipe_info->state = 1; - pipe_info->err_count = 0; - pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pipe_info->stream_urb) - return -ENOMEM; - /* transfer buffer allocated in board_init */ - usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev, - pipe, - pipe_info->transfer_buffer, - pipe_info->transfer_size, - read_pipe_completion, pipe_info); - - DBG("submitting URB %p\n", pipe_info->stream_urb); - retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); - if (retval) { - usb_free_urb(pipe_info->stream_urb); - printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n"); - return retval; - } - - return 0; -} - -static void zr364xx_stop_readpipe(struct zr364xx_camera *cam) -{ - struct zr364xx_pipeinfo *pipe_info; - - if (!cam) { - printk(KERN_ERR KBUILD_MODNAME ": invalid device\n"); - return; - } - DBG("stop read pipe\n"); - pipe_info = cam->pipe; - if (pipe_info) { - if (pipe_info->state != 0) - pipe_info->state = 0; - - if (pipe_info->stream_urb) { - /* cancel urb */ - usb_kill_urb(pipe_info->stream_urb); - usb_free_urb(pipe_info->stream_urb); - pipe_info->stream_urb = NULL; - } - } - return; -} - -/* starts acquisition process */ -static int zr364xx_start_acquire(struct zr364xx_camera *cam) -{ - int j; - - DBG("start acquire\n"); - - cam->last_frame = -1; - cam->cur_frame = 0; - for (j = 0; j < FRAMES; j++) { - cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; - cam->buffer.frame[j].cur_size = 0; - } - cam->b_acquire = 1; - return 0; -} - -static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam) -{ - cam->b_acquire = 0; - return 0; -} - -static int zr364xx_prepare(struct zr364xx_camera *cam) -{ - int res; - int i, j; - - for (i = 0; init[cam->method][i].size != -1; i++) { - res = send_control_msg(cam->udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (res < 0) { - dev_err(&cam->udev->dev, - "error during open sequence: %d\n", i); - return res; - } - } - - cam->skip = 2; - cam->last_frame = -1; - cam->cur_frame = 0; - cam->frame_count = 0; - for (j = 0; j < FRAMES; j++) { - cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; - cam->buffer.frame[j].cur_size = 0; - } - v4l2_ctrl_handler_setup(&cam->ctrl_handler); - return 0; -} - -static int zr364xx_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct zr364xx_camera *cam = video_drvdata(file); - int res; - - DBG("%s\n", __func__); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->owner && cam->owner != priv) - return -EBUSY; - - res = zr364xx_prepare(cam); - if (res) - return res; - res = videobuf_streamon(&cam->vb_vidq); - if (res == 0) { - zr364xx_start_acquire(cam); - cam->owner = file->private_data; - } - return res; -} - -static int zr364xx_vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct zr364xx_camera *cam = video_drvdata(file); - - DBG("%s\n", __func__); - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (cam->owner && cam->owner != priv) - return -EBUSY; - zr364xx_stop_acquire(cam); - return videobuf_streamoff(&cam->vb_vidq); -} - - -/* open the camera */ -static int zr364xx_open(struct file *file) -{ - struct zr364xx_camera *cam = video_drvdata(file); - int err; - - DBG("%s\n", __func__); - - if (mutex_lock_interruptible(&cam->lock)) - return -ERESTARTSYS; - - err = v4l2_fh_open(file); - if (err) - goto out; - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - err = 0; - -out: - mutex_unlock(&cam->lock); - DBG("%s: %d\n", __func__, err); - return err; -} - -static void zr364xx_board_uninit(struct zr364xx_camera *cam) -{ - unsigned long i; - - zr364xx_stop_readpipe(cam); - - /* release sys buffers */ - for (i = 0; i < FRAMES; i++) { - if (cam->buffer.frame[i].lpvbits) { - DBG("vfree %p\n", cam->buffer.frame[i].lpvbits); - vfree(cam->buffer.frame[i].lpvbits); - } - cam->buffer.frame[i].lpvbits = NULL; - } - - /* release transfer buffer */ - kfree(cam->pipe->transfer_buffer); -} - -static void zr364xx_release(struct v4l2_device *v4l2_dev) -{ - struct zr364xx_camera *cam = - container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev); - - videobuf_mmap_free(&cam->vb_vidq); - v4l2_ctrl_handler_free(&cam->ctrl_handler); - zr364xx_board_uninit(cam); - v4l2_device_unregister(&cam->v4l2_dev); - kfree(cam); -} - -/* release the camera */ -static int zr364xx_close(struct file *file) -{ - struct zr364xx_camera *cam; - struct usb_device *udev; - int i; - - DBG("%s\n", __func__); - cam = video_drvdata(file); - - mutex_lock(&cam->lock); - udev = cam->udev; - - if (file->private_data == cam->owner) { - /* turn off stream */ - if (cam->b_acquire) - zr364xx_stop_acquire(cam); - videobuf_streamoff(&cam->vb_vidq); - - for (i = 0; i < 2; i++) { - send_control_msg(udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - } - cam->owner = NULL; - } - - /* Added some delay here, since opening/closing the camera quickly, - * like Ekiga does during its startup, can crash the webcam - */ - mdelay(100); - mutex_unlock(&cam->lock); - return v4l2_fh_release(file); -} - - -static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct zr364xx_camera *cam = video_drvdata(file); - int ret; - - if (!cam) { - DBG("%s: cam == NULL\n", __func__); - return -ENODEV; - } - DBG("mmap called, vma=%p\n", vma); - - ret = videobuf_mmap_mapper(&cam->vb_vidq, vma); - - DBG("vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); - return ret; -} - -static __poll_t zr364xx_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct zr364xx_camera *cam = video_drvdata(file); - struct videobuf_queue *q = &cam->vb_vidq; - __poll_t res = v4l2_ctrl_poll(file, wait); - - _DBG("%s\n", __func__); - - return res | videobuf_poll_stream(file, q, wait); -} - -static const struct v4l2_ctrl_ops zr364xx_ctrl_ops = { - .s_ctrl = zr364xx_s_ctrl, -}; - -static const struct v4l2_file_operations zr364xx_fops = { - .owner = THIS_MODULE, - .open = zr364xx_open, - .release = zr364xx_close, - .read = zr364xx_read, - .mmap = zr364xx_mmap, - .unlocked_ioctl = video_ioctl2, - .poll = zr364xx_poll, -}; - -static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { - .vidioc_querycap = zr364xx_vidioc_querycap, - .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = zr364xx_vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = zr364xx_vidioc_g_fmt_vid_cap, - .vidioc_enum_input = zr364xx_vidioc_enum_input, - .vidioc_g_input = zr364xx_vidioc_g_input, - .vidioc_s_input = zr364xx_vidioc_s_input, - .vidioc_streamon = zr364xx_vidioc_streamon, - .vidioc_streamoff = zr364xx_vidioc_streamoff, - .vidioc_reqbufs = zr364xx_vidioc_reqbufs, - .vidioc_querybuf = zr364xx_vidioc_querybuf, - .vidioc_qbuf = zr364xx_vidioc_qbuf, - .vidioc_dqbuf = zr364xx_vidioc_dqbuf, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static const struct video_device zr364xx_template = { - .name = DRIVER_DESC, - .fops = &zr364xx_fops, - .ioctl_ops = &zr364xx_ioctl_ops, - .release = video_device_release_empty, - .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING, -}; - - - -/*******************/ -/* USB integration */ -/*******************/ -static int zr364xx_board_init(struct zr364xx_camera *cam) -{ - struct zr364xx_pipeinfo *pipe = cam->pipe; - unsigned long i; - int err; - - DBG("board init: %p\n", cam); - memset(pipe, 0, sizeof(*pipe)); - pipe->cam = cam; - pipe->transfer_size = BUFFER_SIZE; - - pipe->transfer_buffer = kzalloc(pipe->transfer_size, - GFP_KERNEL); - if (!pipe->transfer_buffer) { - DBG("out of memory!\n"); - return -ENOMEM; - } - - cam->b_acquire = 0; - cam->frame_count = 0; - - /*** start create system buffers ***/ - for (i = 0; i < FRAMES; i++) { - /* always allocate maximum size for system buffers */ - cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE); - - DBG("valloc %p, idx %lu, pdata %p\n", - &cam->buffer.frame[i], i, - cam->buffer.frame[i].lpvbits); - if (!cam->buffer.frame[i].lpvbits) { - printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n"); - break; - } - } - - if (i == 0) { - printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n"); - err = -ENOMEM; - goto err_free; - } else - cam->buffer.dwFrames = i; - - /* make sure internal states are set */ - for (i = 0; i < FRAMES; i++) { - cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE; - cam->buffer.frame[i].cur_size = 0; - } - - cam->cur_frame = 0; - cam->last_frame = -1; - /*** end create system buffers ***/ - - /* start read pipe */ - err = zr364xx_start_readpipe(cam); - if (err) - goto err_free_frames; - - DBG(": board initialized\n"); - return 0; - -err_free_frames: - for (i = 0; i < FRAMES; i++) - vfree(cam->buffer.frame[i].lpvbits); -err_free: - kfree(cam->pipe->transfer_buffer); - cam->pipe->transfer_buffer = NULL; - return err; -} - -static int zr364xx_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct zr364xx_camera *cam = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - struct v4l2_ctrl_handler *hdl; - int err; - int i; - - DBG("probing...\n"); - - dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n"); - dev_info(&intf->dev, "model %04x:%04x detected\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - cam = kzalloc(sizeof(*cam), GFP_KERNEL); - if (!cam) - return -ENOMEM; - - err = v4l2_device_register(&intf->dev, &cam->v4l2_dev); - if (err < 0) { - dev_err(&udev->dev, "couldn't register v4l2_device\n"); - goto free_cam; - } - hdl = &cam->ctrl_handler; - v4l2_ctrl_handler_init(hdl, 1); - v4l2_ctrl_new_std(hdl, &zr364xx_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 127, 1, 64); - if (hdl->error) { - err = hdl->error; - dev_err(&udev->dev, "couldn't register control\n"); - goto free_hdlr_and_unreg_dev; - } - /* save the init method used by this camera */ - cam->method = id->driver_info; - mutex_init(&cam->lock); - cam->vdev = zr364xx_template; - cam->vdev.lock = &cam->lock; - cam->vdev.v4l2_dev = &cam->v4l2_dev; - cam->vdev.ctrl_handler = &cam->ctrl_handler; - video_set_drvdata(&cam->vdev, cam); - - cam->udev = udev; - - switch (mode) { - case 1: - dev_info(&udev->dev, "160x120 mode selected\n"); - cam->width = 160; - cam->height = 120; - break; - case 2: - dev_info(&udev->dev, "640x480 mode selected\n"); - cam->width = 640; - cam->height = 480; - break; - default: - dev_info(&udev->dev, "320x240 mode selected\n"); - cam->width = 320; - cam->height = 240; - break; - } - - m0d1[0] = mode; - m1[2].value = 0xf000 + mode; - m2[1].value = 0xf000 + mode; - - /* special case for METHOD3, the modes are different */ - if (cam->method == METHOD3) { - switch (mode) { - case 1: - m2[1].value = 0xf000 + 4; - break; - case 2: - m2[1].value = 0xf000 + 0; - break; - default: - m2[1].value = 0xf000 + 1; - break; - } - } - - header2[437] = cam->height / 256; - header2[438] = cam->height % 256; - header2[439] = cam->width / 256; - header2[440] = cam->width % 256; - - cam->nb = 0; - - DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf); - - /* set up the endpoint information */ - iface_desc = intf->cur_altsetting; - DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints); - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { - /* we found the bulk in endpoint */ - cam->read_endpoint = endpoint->bEndpointAddress; - } - } - - if (!cam->read_endpoint) { - err = -ENOMEM; - dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); - goto free_hdlr_and_unreg_dev; - } - - /* v4l */ - INIT_LIST_HEAD(&cam->vidq.active); - cam->vidq.cam = cam; - - usb_set_intfdata(intf, cam); - - /* load zr364xx board specific */ - err = zr364xx_board_init(cam); - if (err) - goto free_hdlr_and_unreg_dev; - err = v4l2_ctrl_handler_setup(hdl); - if (err) - goto board_uninit; - - spin_lock_init(&cam->slock); - - cam->fmt = formats; - - videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops, - NULL, &cam->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_NONE, - sizeof(struct zr364xx_buffer), cam, &cam->lock); - - err = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); - if (err) { - dev_err(&udev->dev, "video_register_device failed\n"); - goto board_uninit; - } - cam->v4l2_dev.release = zr364xx_release; - - dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n", - video_device_node_name(&cam->vdev)); - return 0; - -board_uninit: - zr364xx_board_uninit(cam); -free_hdlr_and_unreg_dev: - v4l2_ctrl_handler_free(hdl); - v4l2_device_unregister(&cam->v4l2_dev); -free_cam: - kfree(cam); - return err; -} - - -static void zr364xx_disconnect(struct usb_interface *intf) -{ - struct zr364xx_camera *cam = usb_get_intfdata(intf); - - mutex_lock(&cam->lock); - usb_set_intfdata(intf, NULL); - dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n"); - video_unregister_device(&cam->vdev); - v4l2_device_disconnect(&cam->v4l2_dev); - - /* stops the read pipe if it is running */ - if (cam->b_acquire) - zr364xx_stop_acquire(cam); - - zr364xx_stop_readpipe(cam); - mutex_unlock(&cam->lock); - v4l2_device_put(&cam->v4l2_dev); -} - - -#ifdef CONFIG_PM -static int zr364xx_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct zr364xx_camera *cam = usb_get_intfdata(intf); - - cam->was_streaming = cam->b_acquire; - if (!cam->was_streaming) - return 0; - zr364xx_stop_acquire(cam); - zr364xx_stop_readpipe(cam); - return 0; -} - -static int zr364xx_resume(struct usb_interface *intf) -{ - struct zr364xx_camera *cam = usb_get_intfdata(intf); - int res; - - if (!cam->was_streaming) - return 0; - - res = zr364xx_start_readpipe(cam); - if (res) - return res; - - res = zr364xx_prepare(cam); - if (res) - goto err_prepare; - - zr364xx_start_acquire(cam); - return 0; - -err_prepare: - zr364xx_stop_readpipe(cam); - return res; -} -#endif - -/**********************/ -/* Module integration */ -/**********************/ - -static struct usb_driver zr364xx_driver = { - .name = "zr364xx", - .probe = zr364xx_probe, - .disconnect = zr364xx_disconnect, -#ifdef CONFIG_PM - .suspend = zr364xx_suspend, - .resume = zr364xx_resume, - .reset_resume = zr364xx_resume, -#endif - .id_table = device_table -}; - -module_usb_driver(zr364xx_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 5c3cc7de209d..44d87fe30d52 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -779,11 +779,8 @@ static int csi_start(struct csi_priv *priv) goto idmac_stop; /* start the frame interval monitor */ - if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC) { - ret = imx_media_fim_set_stream(priv->fim, output_fi, true); - if (ret) - goto idmac_stop; - } + if (priv->fim && priv->dest == IPU_CSI_DEST_IDMAC) + imx_media_fim_set_stream(priv->fim, output_fi, true); ret = ipu_csi_enable(priv->csi); if (ret) { diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c index fb6590dcfc36..e28a33d9dec7 100644 --- a/drivers/staging/media/imx/imx-media-fim.c +++ b/drivers/staging/media/imx/imx-media-fim.c @@ -68,7 +68,10 @@ struct imx_media_fim { bool stream_on; }; -#define icap_enabled(fim) ((fim)->icap_flags != IRQ_TYPE_NONE) +static bool icap_enabled(struct imx_media_fim *fim) +{ + return fim->icap_flags != IRQ_TYPE_NONE; +} static void update_fim_nominal(struct imx_media_fim *fim, const struct v4l2_fract *fi) @@ -368,12 +371,11 @@ void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp) } /* Called by the subdev in its s_stream callback */ -int imx_media_fim_set_stream(struct imx_media_fim *fim, - const struct v4l2_fract *fi, - bool on) +void imx_media_fim_set_stream(struct imx_media_fim *fim, + const struct v4l2_fract *fi, + bool on) { unsigned long flags; - int ret = 0; v4l2_ctrl_lock(fim->ctrl[FIM_CL_ENABLE]); @@ -393,7 +395,6 @@ int imx_media_fim_set_stream(struct imx_media_fim *fim, fim->stream_on = on; out: v4l2_ctrl_unlock(fim->ctrl[FIM_CL_ENABLE]); - return ret; } int imx_media_fim_add_controls(struct imx_media_fim *fim) diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index f679249d82e4..6f9a46573edd 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -246,9 +246,9 @@ int imx_media_dev_notifier_register(struct imx_media_dev *imxmd, /* imx-media-fim.c */ struct imx_media_fim; void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp); -int imx_media_fim_set_stream(struct imx_media_fim *fim, - const struct v4l2_fract *frame_interval, - bool on); +void imx_media_fim_set_stream(struct imx_media_fim *fim, + const struct v4l2_fract *frame_interval, + bool on); int imx_media_fim_add_controls(struct imx_media_fim *fim); struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd); void imx_media_fim_free(struct imx_media_fim *fim); diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c index 86ccc8937afc..7b15fc54efe4 100644 --- a/drivers/staging/media/meson/vdec/esparser.c +++ b/drivers/staging/media/meson/vdec/esparser.c @@ -314,8 +314,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) num_dst_bufs = codec_ops->num_pending_bufs(sess); num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); - if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) - num_dst_bufs -= 3; + num_dst_bufs -= 3; if (esparser_vififo_get_free_space(sess) < payload_size || atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 0ad70faa9ba0..05548eab7daa 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -201,39 +201,34 @@ iss_video_remote_subdev(struct iss_video *video, u32 *pad) /* Return a pointer to the ISS video instance at the far end of the pipeline. */ static struct iss_video * -iss_video_far_end(struct iss_video *video) +iss_video_far_end(struct iss_video *video, struct iss_pipeline *pipe) { - struct media_graph graph; - struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_pipeline_entity_iter iter; + struct media_entity *entity; struct iss_video *far_end = NULL; + int ret; - mutex_lock(&mdev->graph_mutex); - - if (media_graph_walk_init(&graph, mdev)) { - mutex_unlock(&mdev->graph_mutex); - return NULL; - } + ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter); + if (ret) + return ERR_PTR(-ENOMEM); - media_graph_walk_start(&graph, entity); + media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) { + struct iss_video *other; - while ((entity = media_graph_walk_next(&graph))) { if (entity == &video->video.entity) continue; if (!is_media_entity_v4l2_video_device(entity)) continue; - far_end = to_iss_video(media_entity_to_video_device(entity)); - if (far_end->type != video->type) + other = to_iss_video(media_entity_to_video_device(entity)); + if (other->type != video->type) { + far_end = other; break; - - far_end = NULL; + } } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&graph); + media_pipeline_entity_iter_cleanup(&iter); return far_end; } @@ -850,12 +845,12 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { struct iss_video_fh *vfh = to_iss_video_fh(fh); struct iss_video *video = video_drvdata(file); - struct media_graph graph; - struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->graph_obj.mdev; + struct media_device *mdev = video->video.entity.graph_obj.mdev; + struct media_pipeline_pad_iter iter; enum iss_pipeline_state state; struct iss_pipeline *pipe; struct iss_video *far_end; + struct media_pad *pad; unsigned long flags; int ret; @@ -873,13 +868,9 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) pipe->external_rate = 0; pipe->external_bpp = 0; - ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev); - if (ret) - goto err_graph_walk_init; - - ret = media_graph_walk_init(&graph, entity->graph_obj.mdev); + ret = media_entity_enum_init(&pipe->ent_enum, mdev); if (ret) - goto err_graph_walk_init; + goto err_entity_enum_init; if (video->iss->pdata->set_constraints) video->iss->pdata->set_constraints(video->iss, true); @@ -888,11 +879,8 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) if (ret < 0) goto err_media_pipeline_start; - mutex_lock(&mdev->graph_mutex); - media_graph_walk_start(&graph, entity); - while ((entity = media_graph_walk_next(&graph))) - media_entity_enum_set(&pipe->ent_enum, entity); - mutex_unlock(&mdev->graph_mutex); + media_pipeline_for_each_pad(&pipe->pipe, &iter, pad) + media_entity_enum_set(&pipe->ent_enum, pad->entity); /* * Verify that the currently configured format matches the output of @@ -909,7 +897,11 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) * Find the ISS video node connected at the far end of the pipeline and * update the pipeline. */ - far_end = iss_video_far_end(video); + far_end = iss_video_far_end(video, pipe); + if (IS_ERR(far_end)) { + ret = PTR_ERR(far_end); + goto err_iss_video_check_format; + } if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT; @@ -966,8 +958,6 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) spin_unlock_irqrestore(&video->qlock, flags); } - media_graph_walk_cleanup(&graph); - mutex_unlock(&video->stream_lock); return 0; @@ -981,9 +971,7 @@ err_media_pipeline_start: video->iss->pdata->set_constraints(video->iss, false); video->queue = NULL; - media_graph_walk_cleanup(&graph); - -err_graph_walk_init: +err_entity_enum_init: media_entity_enum_cleanup(&pipe->ent_enum); mutex_unlock(&video->stream_lock); diff --git a/include/media/davinci/ccdc_types.h b/include/media/davinci/ccdc_types.h deleted file mode 100644 index 971984dc1ce4..000000000000 --- a/include/media/davinci/ccdc_types.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - **************************************************************************/ -#ifndef _CCDC_TYPES_H -#define _CCDC_TYPES_H -enum ccdc_pixfmt { - CCDC_PIXFMT_RAW, - CCDC_PIXFMT_YCBCR_16BIT, - CCDC_PIXFMT_YCBCR_8BIT -}; - -enum ccdc_frmfmt { - CCDC_FRMFMT_PROGRESSIVE, - CCDC_FRMFMT_INTERLACED -}; - -/* PIXEL ORDER IN MEMORY from LSB to MSB */ -/* only applicable for 8-bit input mode */ -enum ccdc_pixorder { - CCDC_PIXORDER_YCBYCR, - CCDC_PIXORDER_CBYCRY, -}; - -enum ccdc_buftype { - CCDC_BUFTYPE_FLD_INTERLEAVED, - CCDC_BUFTYPE_FLD_SEPARATED -}; -#endif diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146.h b/include/media/drv-intf/saa7146.h index 71ce63c99cb4..71ce63c99cb4 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146.h +++ b/include/media/drv-intf/saa7146.h diff --git a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h index d7bd916fe3ad..635805fb35e8 100644 --- a/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h +++ b/include/media/drv-intf/saa7146_vv.h @@ -5,8 +5,8 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-fh.h> +#include <media/drv-intf/saa7146.h> #include <media/videobuf-dma-sg.h> -#include "saa7146.h" #define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ diff --git a/include/media/i2c/s5c73m3.h b/include/media/i2c/s5c73m3.h deleted file mode 100644 index df0769d64523..000000000000 --- a/include/media/i2c/s5c73m3.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Samsung LSI S5C73M3 8M pixel camera driver - * - * Copyright (C) 2012, Samsung Electronics, Co., Ltd. - * Sylwester Nawrocki <s.nawrocki@samsung.com> - * Andrzej Hajda <a.hajda@samsung.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef MEDIA_S5C73M3__ -#define MEDIA_S5C73M3__ - -#include <linux/videodev2.h> -#include <media/v4l2-mediabus.h> - -/** - * struct s5c73m3_platform_data - s5c73m3 driver platform data - * @mclk_frequency: sensor's master clock frequency in Hz - * @bus_type: bus type - * @nlanes: maximum number of MIPI-CSI lanes used - * @horiz_flip: default horizontal image flip value, non zero to enable - * @vert_flip: default vertical image flip value, non zero to enable - */ - -struct s5c73m3_platform_data { - unsigned long mclk_frequency; - - enum v4l2_mbus_type bus_type; - u8 nlanes; - u8 horiz_flip; - u8 vert_flip; -}; - -#endif /* MEDIA_S5C73M3__ */ diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 85ed08ddee9d..741f9c629c6f 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -131,6 +131,26 @@ struct media_pipeline_pad { }; /** + * struct media_pipeline_pad_iter - Iterator for media_pipeline_for_each_pad + * + * @cursor: The current element + */ +struct media_pipeline_pad_iter { + struct list_head *cursor; +}; + +/** + * struct media_pipeline_entity_iter - Iterator for media_pipeline_for_each_entity + * + * @ent_enum: The entity enumeration tracker + * @cursor: The current element + */ +struct media_pipeline_entity_iter { + struct media_entity_enum ent_enum; + struct list_head *cursor; +}; + +/** * struct media_link - A link object part of a media graph. * * @graph_obj: Embedded structure containing the media object common data @@ -242,7 +262,9 @@ struct media_pad { * part of the same pipeline and enabling one of the pads * means that the other pad will become "locked" and * doesn't allow configuration changes. pad0 and pad1 are - * guaranteed to not both be sinks or sources. + * guaranteed to not both be sinks or sources. Never call + * the .has_pad_interdep() operation directly, always use + * media_entity_has_pad_interdep(). * Optional: If the operation isn't implemented all pads * will be considered as interdependent. * @@ -1066,6 +1088,8 @@ int media_entity_get_fwnode_pad(struct media_entity *entity, * @graph: Media graph structure that will be used to walk the graph * @mdev: Pointer to the &media_device that contains the object * + * This function is deprecated, use media_pipeline_for_each_pad() instead. + * * The caller is required to hold the media_device graph_mutex during the graph * walk until the graph state is released. * @@ -1078,6 +1102,8 @@ __must_check int media_graph_walk_init( * media_graph_walk_cleanup - Release resources used by graph walk. * * @graph: Media graph structure that will be used to walk the graph + * + * This function is deprecated, use media_pipeline_for_each_pad() instead. */ void media_graph_walk_cleanup(struct media_graph *graph); @@ -1088,6 +1114,8 @@ void media_graph_walk_cleanup(struct media_graph *graph); * @graph: Media graph structure that will be used to walk the graph * @entity: Starting entity * + * This function is deprecated, use media_pipeline_for_each_pad() instead. + * * Before using this function, media_graph_walk_init() must be * used to allocate resources used for walking the graph. This * function initializes the graph traversal structure to walk the @@ -1103,6 +1131,8 @@ void media_graph_walk_start(struct media_graph *graph, * media_graph_walk_next - Get the next entity in the graph * @graph: Media graph structure * + * This function is deprecated, use media_pipeline_for_each_pad() instead. + * * Perform a depth-first traversal of the given media entities graph. * * The graph structure must have been previously initialized with a call to @@ -1163,6 +1193,76 @@ void media_pipeline_stop(struct media_pad *pad); */ void __media_pipeline_stop(struct media_pad *pad); +struct media_pad * +__media_pipeline_pad_iter_next(struct media_pipeline *pipe, + struct media_pipeline_pad_iter *iter, + struct media_pad *pad); + +/** + * media_pipeline_for_each_pad - Iterate on all pads in a media pipeline + * @pipe: The pipeline + * @iter: The iterator (struct media_pipeline_pad_iter) + * @pad: The iterator pad + * + * Iterate on all pads in a media pipeline. This is only valid after the + * pipeline has been built with media_pipeline_start() and before it gets + * destroyed with media_pipeline_stop(). + */ +#define media_pipeline_for_each_pad(pipe, iter, pad) \ + for (pad = __media_pipeline_pad_iter_next((pipe), iter, NULL); \ + pad != NULL; \ + pad = __media_pipeline_pad_iter_next((pipe), iter, pad)) + +/** + * media_pipeline_entity_iter_init - Initialize a pipeline entity iterator + * @pipe: The pipeline + * @iter: The iterator + * + * This function must be called to initialize the iterator before using it in a + * media_pipeline_for_each_entity() loop. The iterator must be destroyed by a + * call to media_pipeline_entity_iter_cleanup after the loop (including in code + * paths that break from the loop). + * + * The same iterator can be used in multiple consecutive loops without being + * destroyed and reinitialized. + * + * Return: 0 on success or a negative error code otherwise. + */ +int media_pipeline_entity_iter_init(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter); + +/** + * media_pipeline_entity_iter_cleanup - Destroy a pipeline entity iterator + * @iter: The iterator + * + * This function must be called to destroy iterators initialized with + * media_pipeline_entity_iter_init(). + */ +void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter); + +struct media_entity * +__media_pipeline_entity_iter_next(struct media_pipeline *pipe, + struct media_pipeline_entity_iter *iter, + struct media_entity *entity); + +/** + * media_pipeline_for_each_entity - Iterate on all entities in a media pipeline + * @pipe: The pipeline + * @iter: The iterator (struct media_pipeline_entity_iter) + * @entity: The iterator entity + * + * Iterate on all entities in a media pipeline. This is only valid after the + * pipeline has been built with media_pipeline_start() and before it gets + * destroyed with media_pipeline_stop(). The iterator must be initialized with + * media_pipeline_entity_iter_init() before iteration, and destroyed with + * media_pipeline_entity_iter_cleanup() after (including in code paths that + * break from the loop). + */ +#define media_pipeline_for_each_entity(pipe, iter, entity) \ + for (entity = __media_pipeline_entity_iter_next((pipe), iter, NULL); \ + entity != NULL; \ + entity = __media_pipeline_entity_iter_next((pipe), iter, entity)) + /** * media_pipeline_alloc_start - Mark a pipeline as streaming * @pad: Starting pad diff --git a/include/media/ov_16bit_addr_reg_helpers.h b/include/media/ov_16bit_addr_reg_helpers.h new file mode 100644 index 000000000000..1c60a50bd795 --- /dev/null +++ b/include/media/ov_16bit_addr_reg_helpers.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * I2C register access helpers for Omnivision OVxxxx image sensors which expect + * a 16 bit register address in big-endian format and which have 1-3 byte + * wide registers, in big-endian format (for the higher width registers). + * + * Based on the register helpers from drivers/media/i2c/ov2680.c which is: + * Copyright (C) 2018 Linaro Ltd + */ +#ifndef __OV_16BIT_ADDR_REG_HELPERS_H +#define __OV_16BIT_ADDR_REG_HELPERS_H + +#include <asm/unaligned.h> +#include <linux/dev_printk.h> +#include <linux/i2c.h> + +static inline int ov_read_reg(struct i2c_client *client, u16 reg, + unsigned int len, u32 *val) +{ + u8 addr_buf[2], data_buf[4] = { }; + struct i2c_msg msgs[2]; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) { + dev_err(&client->dev, "read error: reg=0x%4x: %d\n", reg, ret); + return -EIO; + } + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +#define ov_read_reg8(s, r, v) ov_read_reg(s, r, 1, v) +#define ov_read_reg16(s, r, v) ov_read_reg(s, r, 2, v) +#define ov_read_reg24(s, r, v) ov_read_reg(s, r, 3, v) + +static inline int ov_write_reg(struct i2c_client *client, u16 reg, + unsigned int len, u32 val) +{ + u8 buf[6]; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + ret = i2c_master_send(client, buf, len + 2); + if (ret != len + 2) { + dev_err(&client->dev, "write error: reg=0x%4x: %d\n", reg, ret); + return -EIO; + } + + return 0; +} + +#define ov_write_reg8(s, r, v) ov_write_reg(s, r, 1, v) +#define ov_write_reg16(s, r, v) ov_write_reg(s, r, 2, v) +#define ov_write_reg24(s, r, v) ov_write_reg(s, r, 3, v) + +static inline int ov_update_reg(struct i2c_client *client, u16 reg, u8 mask, u8 val) +{ + u32 readval; + int ret; + + ret = ov_read_reg8(client, reg, &readval); + if (ret < 0) + return ret; + + val = (readval & ~mask) | (val & mask); + + return ov_write_reg8(client, reg, val); +} + +#endif diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index f3fe9b6e26d4..7245887ef002 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -346,6 +346,7 @@ enum v4l2_mbus_frame_desc_flags { * struct v4l2_mbus_frame_desc_entry - media bus frame description structure * * @flags: bitmask flags, as defined by &enum v4l2_mbus_frame_desc_flags. + * @stream: stream in routing configuration * @pixelcode: media bus pixel code, valid if @flags * %FRAME_DESC_FL_BLOB is not set. * @length: number of octets per frame, valid if @flags @@ -355,6 +356,7 @@ enum v4l2_mbus_frame_desc_flags { */ struct v4l2_mbus_frame_desc_entry { enum v4l2_mbus_frame_desc_flags flags; + u32 stream; u32 pixelcode; u32 length; union { @@ -702,11 +704,59 @@ struct v4l2_subdev_pad_config { }; /** + * struct v4l2_subdev_stream_config - Used for storing stream configuration. + * + * @pad: pad number + * @stream: stream number + * @enabled: has the stream been enabled with v4l2_subdev_enable_stream() + * @fmt: &struct v4l2_mbus_framefmt + * @crop: &struct v4l2_rect to be used for crop + * @compose: &struct v4l2_rect to be used for compose + * + * This structure stores configuration for a stream. + */ +struct v4l2_subdev_stream_config { + u32 pad; + u32 stream; + bool enabled; + + struct v4l2_mbus_framefmt fmt; + struct v4l2_rect crop; + struct v4l2_rect compose; +}; + +/** + * struct v4l2_subdev_stream_configs - A collection of stream configs. + * + * @num_configs: number of entries in @config. + * @configs: an array of &struct v4l2_subdev_stream_configs. + */ +struct v4l2_subdev_stream_configs { + u32 num_configs; + struct v4l2_subdev_stream_config *configs; +}; + +/** + * struct v4l2_subdev_krouting - subdev routing table + * + * @num_routes: number of routes + * @routes: &struct v4l2_subdev_route + * + * This structure contains the routing table for a subdev. + */ +struct v4l2_subdev_krouting { + unsigned int num_routes; + struct v4l2_subdev_route *routes; +}; + +/** * struct v4l2_subdev_state - Used for storing subdev state information. * * @_lock: default for 'lock' * @lock: mutex for the state. May be replaced by the user. * @pads: &struct v4l2_subdev_pad_config array + * @routing: routing table for the subdev + * @stream_configs: stream configurations (only for V4L2_SUBDEV_FL_STREAMS) * * This structure only needs to be passed to the pad op if the 'which' field * of the main argument is set to %V4L2_SUBDEV_FORMAT_TRY. For @@ -717,6 +767,8 @@ struct v4l2_subdev_state { struct mutex _lock; struct mutex *lock; struct v4l2_subdev_pad_config *pads; + struct v4l2_subdev_krouting routing; + struct v4l2_subdev_stream_configs stream_configs; }; /** @@ -769,6 +821,21 @@ struct v4l2_subdev_state { * this operation as close as possible to stream on time. The * operation shall fail if the pad index it has been called on * is not valid or in case of unrecoverable failures. + * + * @set_routing: enable or disable data connection routes described in the + * subdevice routing table. + * + * @enable_streams: Enable the streams defined in streams_mask on the given + * source pad. Subdevs that implement this operation must use the active + * state management provided by the subdev core (enabled through a call to + * v4l2_subdev_init_finalize() at initialization time). Do not call + * directly, use v4l2_subdev_enable_streams() instead. + * + * @disable_streams: Disable the streams defined in streams_mask on the given + * source pad. Subdevs that implement this operation must use the active + * state management provided by the subdev core (enabled through a call to + * v4l2_subdev_init_finalize() at initialization time). Do not call + * directly, use v4l2_subdev_disable_streams() instead. */ struct v4l2_subdev_pad_ops { int (*init_cfg)(struct v4l2_subdev *sd, @@ -811,6 +878,16 @@ struct v4l2_subdev_pad_ops { struct v4l2_mbus_frame_desc *fd); int (*get_mbus_config)(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_config *config); + int (*set_routing)(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *route); + int (*enable_streams)(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask); + int (*disable_streams)(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask); }; /** @@ -885,6 +962,17 @@ struct v4l2_subdev_internal_ops { * should set this flag. */ #define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3) +/* + * Set this flag if this subdev supports multiplexed streams. This means + * that the driver supports routing and handles the stream parameter in its + * v4l2_subdev_pad_ops handlers. More specifically, this means: + * + * - Centrally managed subdev active state is enabled + * - Legacy pad config is _not_ supported (state->pads is NULL) + * - Routing ioctls are available + * - Multiple streams per pad are supported + */ +#define V4L2_SUBDEV_FL_STREAMS (1U << 4) struct regulator_bulk_data; @@ -946,6 +1034,10 @@ struct v4l2_subdev_platform_data { * @active_state: Active state for the subdev (NULL for subdevs tracking the * state internally). Initialized by calling * v4l2_subdev_init_finalize(). + * @enabled_streams: Bitmask of enabled streams used by + * v4l2_subdev_enable_streams() and + * v4l2_subdev_disable_streams() helper functions for fallback + * cases. * * Each instance of a subdev driver should create this struct, either * stand-alone or embedded in a larger struct. @@ -993,6 +1085,7 @@ struct v4l2_subdev { * doesn't support it. */ struct v4l2_subdev_state *active_state; + u64 enabled_streams; }; @@ -1218,6 +1311,24 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, int v4l2_subdev_link_validate(struct media_link *link); /** + * v4l2_subdev_has_pad_interdep - MC has_pad_interdep implementation for subdevs + * + * @entity: pointer to &struct media_entity + * @pad0: pad number for the first pad + * @pad1: pad number for the second pad + * + * This function is an implementation of the + * media_entity_operations.has_pad_interdep operation for subdevs that + * implement the multiplexed streams API (as indicated by the + * V4L2_SUBDEV_FL_STREAMS subdev flag). + * + * It considers two pads interdependent if there is an active route between pad0 + * and pad1. + */ +bool v4l2_subdev_has_pad_interdep(struct media_entity *entity, + unsigned int pad0, unsigned int pad1); + +/** * __v4l2_subdev_state_alloc - allocate v4l2_subdev_state * * @sd: pointer to &struct v4l2_subdev for which the state is being allocated. @@ -1377,6 +1488,272 @@ v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd) int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format); +/** + * v4l2_subdev_set_routing() - Set given routing to subdev state + * @sd: The subdevice + * @state: The subdevice state + * @routing: Routing that will be copied to subdev state + * + * This will release old routing table (if any) from the state, allocate + * enough space for the given routing, and copy the routing. + * + * This can be used from the subdev driver's set_routing op, after validating + * the routing. + */ +int v4l2_subdev_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + const struct v4l2_subdev_krouting *routing); + +struct v4l2_subdev_route * +__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing, + struct v4l2_subdev_route *route); + +/** + * for_each_active_route - iterate on all active routes of a routing table + * @routing: The routing table + * @route: The route iterator + */ +#define for_each_active_route(routing, route) \ + for ((route) = NULL; \ + ((route) = __v4l2_subdev_next_active_route((routing), (route)));) + +/** + * v4l2_subdev_set_routing_with_fmt() - Set given routing and format to subdev + * state + * @sd: The subdevice + * @state: The subdevice state + * @routing: Routing that will be copied to subdev state + * @fmt: Format used to initialize all the streams + * + * This is the same as v4l2_subdev_set_routing, but additionally initializes + * all the streams using the given format. + */ +int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing, + const struct v4l2_mbus_framefmt *fmt); + +/** + * v4l2_subdev_state_get_stream_format() - Get pointer to a stream format + * @state: subdevice state + * @pad: pad id + * @stream: stream id + * + * This returns a pointer to &struct v4l2_mbus_framefmt for the given pad + + * stream in the subdev state. + * + * If the state does not contain the given pad + stream, NULL is returned. + */ +struct v4l2_mbus_framefmt * +v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream); + +/** + * v4l2_subdev_state_get_stream_crop() - Get pointer to a stream crop rectangle + * @state: subdevice state + * @pad: pad id + * @stream: stream id + * + * This returns a pointer to crop rectangle for the given pad + stream in the + * subdev state. + * + * If the state does not contain the given pad + stream, NULL is returned. + */ +struct v4l2_rect * +v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream); + +/** + * v4l2_subdev_state_get_stream_compose() - Get pointer to a stream compose + * rectangle + * @state: subdevice state + * @pad: pad id + * @stream: stream id + * + * This returns a pointer to compose rectangle for the given pad + stream in the + * subdev state. + * + * If the state does not contain the given pad + stream, NULL is returned. + */ +struct v4l2_rect * +v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state, + unsigned int pad, u32 stream); + +/** + * v4l2_subdev_routing_find_opposite_end() - Find the opposite stream + * @routing: routing used to find the opposite side + * @pad: pad id + * @stream: stream id + * @other_pad: pointer used to return the opposite pad + * @other_stream: pointer used to return the opposite stream + * + * This function uses the routing table to find the pad + stream which is + * opposite the given pad + stream. + * + * @other_pad and/or @other_stream can be NULL if the caller does not need the + * value. + * + * Returns 0 on success, or -EINVAL if no matching route is found. + */ +int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, + u32 pad, u32 stream, u32 *other_pad, + u32 *other_stream); + +/** + * v4l2_subdev_state_get_opposite_stream_format() - Get pointer to opposite + * stream format + * @state: subdevice state + * @pad: pad id + * @stream: stream id + * + * This returns a pointer to &struct v4l2_mbus_framefmt for the pad + stream + * that is opposite the given pad + stream in the subdev state. + * + * If the state does not contain the given pad + stream, NULL is returned. + */ +struct v4l2_mbus_framefmt * +v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state, + u32 pad, u32 stream); + +/** + * v4l2_subdev_state_xlate_streams() - Translate streams from one pad to another + * + * @state: Subdevice state + * @pad0: The first pad + * @pad1: The second pad + * @streams: Streams bitmask on the first pad + * + * Streams on sink pads of a subdev are routed to source pads as expressed in + * the subdev state routing table. Stream numbers don't necessarily match on + * the sink and source side of a route. This function translates stream numbers + * on @pad0, expressed as a bitmask in @streams, to the corresponding streams + * on @pad1 using the routing table from the @state. It returns the stream mask + * on @pad1, and updates @streams with the streams that have been found in the + * routing table. + * + * @pad0 and @pad1 must be a sink and a source, in any order. + * + * Return: The bitmask of streams of @pad1 that are routed to @streams on @pad0. + */ +u64 v4l2_subdev_state_xlate_streams(const struct v4l2_subdev_state *state, + u32 pad0, u32 pad1, u64 *streams); + +/** + * enum v4l2_subdev_routing_restriction - Subdevice internal routing restrictions + * + * @V4L2_SUBDEV_ROUTING_NO_1_TO_N: + * an input stream may not be routed to multiple output streams (stream + * duplication) + * @V4L2_SUBDEV_ROUTING_NO_N_TO_1: + * multiple input streams may not be routed to the same output stream + * (stream merging) + * @V4L2_SUBDEV_ROUTING_NO_STREAM_MIX: + * streams on the same pad may not be routed to streams on different pads + * @V4L2_SUBDEV_ROUTING_ONLY_1_TO_1: + * only non-overlapping 1-to-1 stream routing is allowed (a combination of + * @V4L2_SUBDEV_ROUTING_NO_1_TO_N and @V4L2_SUBDEV_ROUTING_NO_N_TO_1) + */ +enum v4l2_subdev_routing_restriction { + V4L2_SUBDEV_ROUTING_NO_1_TO_N = BIT(0), + V4L2_SUBDEV_ROUTING_NO_N_TO_1 = BIT(1), + V4L2_SUBDEV_ROUTING_NO_STREAM_MIX = BIT(2), + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 = + V4L2_SUBDEV_ROUTING_NO_1_TO_N | + V4L2_SUBDEV_ROUTING_NO_N_TO_1, +}; + +/** + * v4l2_subdev_routing_validate() - Verify that routes comply with driver + * constraints + * @sd: The subdevice + * @routing: Routing to verify + * @disallow: Restrictions on routes + * + * This verifies that the given routing complies with the @disallow constraints. + * + * Returns 0 on success, error value otherwise. + */ +int v4l2_subdev_routing_validate(struct v4l2_subdev *sd, + const struct v4l2_subdev_krouting *routing, + enum v4l2_subdev_routing_restriction disallow); + +/** + * v4l2_subdev_enable_streams() - Enable streams on a pad + * @sd: The subdevice + * @pad: The pad + * @streams_mask: Bitmask of streams to enable + * + * This function enables streams on a source @pad of a subdevice. The pad is + * identified by its index, while the streams are identified by the + * @streams_mask bitmask. This allows enabling multiple streams on a pad at + * once. + * + * Enabling a stream that is already enabled isn't allowed. If @streams_mask + * contains an already enabled stream, this function returns -EALREADY without + * performing any operation. + * + * Per-stream enable is only available for subdevs that implement the + * .enable_streams() and .disable_streams() operations. For other subdevs, this + * function implements a best-effort compatibility by calling the .s_stream() + * operation, limited to subdevs that have a single source pad. + * + * Return: + * * 0: Success + * * -EALREADY: One of the streams in streams_mask is already enabled + * * -EINVAL: The pad index is invalid, or doesn't correspond to a source pad + * * -EOPNOTSUPP: Falling back to the legacy .s_stream() operation is + * impossible because the subdev has multiple source pads + */ +int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask); + +/** + * v4l2_subdev_disable_streams() - Disable streams on a pad + * @sd: The subdevice + * @pad: The pad + * @streams_mask: Bitmask of streams to disable + * + * This function disables streams on a source @pad of a subdevice. The pad is + * identified by its index, while the streams are identified by the + * @streams_mask bitmask. This allows disabling multiple streams on a pad at + * once. + * + * Disabling a streams that is not enabled isn't allowed. If @streams_mask + * contains a disabled stream, this function returns -EALREADY without + * performing any operation. + * + * Per-stream disable is only available for subdevs that implement the + * .enable_streams() and .disable_streams() operations. For other subdevs, this + * function implements a best-effort compatibility by calling the .s_stream() + * operation, limited to subdevs that have a single source pad. + * + * Return: + * * 0: Success + * * -EALREADY: One of the streams in streams_mask is not enabled + * * -EINVAL: The pad index is invalid, or doesn't correspond to a source pad + * * -EOPNOTSUPP: Falling back to the legacy .s_stream() operation is + * impossible because the subdev has multiple source pads + */ +int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad, + u64 streams_mask); + +/** + * v4l2_subdev_s_stream_helper() - Helper to implement the subdev s_stream + * operation using enable_streams and disable_streams + * @sd: The subdevice + * @enable: Enable or disable streaming + * + * Subdevice drivers that implement the streams-aware + * &v4l2_subdev_pad_ops.enable_streams and &v4l2_subdev_pad_ops.disable_streams + * operations can use this helper to implement the legacy + * &v4l2_subdev_video_ops.s_stream operation. + * + * This helper can only be used by subdevs that have a single source pad. + * + * Return: 0 on success, or a negative error code otherwise. + */ +int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable); + #endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */ #endif /* CONFIG_MEDIA_CONTROLLER */ diff --git a/include/uapi/linux/meye.h b/include/uapi/linux/meye.h deleted file mode 100644 index de9e3a954f3d..000000000000 --- a/include/uapi/linux/meye.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net> - * - * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com> - * - * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MEYE_H_ -#define _MEYE_H_ - -/****************************************************************************/ -/* Private API for handling mjpeg capture / playback. */ -/****************************************************************************/ - -struct meye_params { - unsigned char subsample; - unsigned char quality; - unsigned char sharpness; - unsigned char agc; - unsigned char picture; - unsigned char framerate; -}; - -/* query the extended parameters */ -#define MEYEIOC_G_PARAMS _IOR ('v', BASE_VIDIOC_PRIVATE+0, struct meye_params) -/* set the extended parameters */ -#define MEYEIOC_S_PARAMS _IOW ('v', BASE_VIDIOC_PRIVATE+1, struct meye_params) -/* queue a buffer for mjpeg capture */ -#define MEYEIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOC_PRIVATE+2, int) -/* sync a previously queued mjpeg buffer */ -#define MEYEIOC_SYNC _IOWR('v', BASE_VIDIOC_PRIVATE+3, int) -/* get a still uncompressed snapshot */ -#define MEYEIOC_STILLCAPT _IO ('v', BASE_VIDIOC_PRIVATE+4) -/* get a jpeg compressed snapshot */ -#define MEYEIOC_STILLJCAPT _IOR ('v', BASE_VIDIOC_PRIVATE+5, int) - -/* V4L2 private controls */ -#define V4L2_CID_MEYE_AGC (V4L2_CID_USER_MEYE_BASE + 0) -#define V4L2_CID_MEYE_PICTURE (V4L2_CID_USER_MEYE_BASE + 1) -#define V4L2_CID_MEYE_FRAMERATE (V4L2_CID_USER_MEYE_BASE + 2) - -#endif diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index b73a8ba7df6c..5e80daa4ffe0 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -115,9 +115,13 @@ enum v4l2_colorfx { /* USER-class private control IDs */ -/* The base for the meye driver controls. See linux/meye.h for the list - * of controls. We reserve 16 controls for this driver. */ +#ifndef __KERNEL__ +/* + * The base for the meye driver controls. This driver was removed, but + * we keep this define in case any software still uses it. + */ #define V4L2_CID_USER_MEYE_BASE (V4L2_CID_USER_BASE + 0x1000) +#endif /* The base for the bttv driver controls. * We reserve 32 controls for this driver. */ diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h index ecce4c79f5c5..654d659de835 100644 --- a/include/uapi/linux/v4l2-subdev.h +++ b/include/uapi/linux/v4l2-subdev.h @@ -11,6 +11,7 @@ #ifndef __LINUX_V4L2_SUBDEV_H #define __LINUX_V4L2_SUBDEV_H +#include <linux/const.h> #include <linux/ioctl.h> #include <linux/types.h> #include <linux/v4l2-common.h> @@ -31,13 +32,15 @@ enum v4l2_subdev_format_whence { * @which: format type (from enum v4l2_subdev_format_whence) * @pad: pad number, as reported by the media API * @format: media bus format (format code and frame size) + * @stream: stream number, defined in subdev routing * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_format { __u32 which; __u32 pad; struct v4l2_mbus_framefmt format; - __u32 reserved[8]; + __u32 stream; + __u32 reserved[7]; }; /** @@ -45,13 +48,15 @@ struct v4l2_subdev_format { * @which: format type (from enum v4l2_subdev_format_whence) * @pad: pad number, as reported by the media API * @rect: pad crop rectangle boundaries + * @stream: stream number, defined in subdev routing * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_crop { __u32 which; __u32 pad; struct v4l2_rect rect; - __u32 reserved[8]; + __u32 stream; + __u32 reserved[7]; }; #define V4L2_SUBDEV_MBUS_CODE_CSC_COLORSPACE 0x00000001 @@ -67,6 +72,7 @@ struct v4l2_subdev_crop { * @code: format code (MEDIA_BUS_FMT_ definitions) * @which: format type (from enum v4l2_subdev_format_whence) * @flags: flags set by the driver, (V4L2_SUBDEV_MBUS_CODE_*) + * @stream: stream number, defined in subdev routing * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_mbus_code_enum { @@ -75,7 +81,8 @@ struct v4l2_subdev_mbus_code_enum { __u32 code; __u32 which; __u32 flags; - __u32 reserved[7]; + __u32 stream; + __u32 reserved[6]; }; /** @@ -88,6 +95,7 @@ struct v4l2_subdev_mbus_code_enum { * @min_height: minimum frame height, in pixels * @max_height: maximum frame height, in pixels * @which: format type (from enum v4l2_subdev_format_whence) + * @stream: stream number, defined in subdev routing * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_frame_size_enum { @@ -99,19 +107,22 @@ struct v4l2_subdev_frame_size_enum { __u32 min_height; __u32 max_height; __u32 which; - __u32 reserved[8]; + __u32 stream; + __u32 reserved[7]; }; /** * struct v4l2_subdev_frame_interval - Pad-level frame rate * @pad: pad number, as reported by the media API * @interval: frame interval in seconds + * @stream: stream number, defined in subdev routing * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_frame_interval { __u32 pad; struct v4l2_fract interval; - __u32 reserved[9]; + __u32 stream; + __u32 reserved[8]; }; /** @@ -123,6 +134,7 @@ struct v4l2_subdev_frame_interval { * @height: frame height in pixels * @interval: frame interval in seconds * @which: format type (from enum v4l2_subdev_format_whence) + * @stream: stream number, defined in subdev routing * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_frame_interval_enum { @@ -133,7 +145,8 @@ struct v4l2_subdev_frame_interval_enum { __u32 height; struct v4l2_fract interval; __u32 which; - __u32 reserved[8]; + __u32 stream; + __u32 reserved[7]; }; /** @@ -145,6 +158,7 @@ struct v4l2_subdev_frame_interval_enum { * defined in v4l2-common.h; V4L2_SEL_TGT_* . * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*. * @r: coordinates of the selection window + * @stream: stream number, defined in subdev routing * @reserved: for future use, set to zero for now * * Hardware may use multiple helper windows to process a video stream. @@ -157,7 +171,8 @@ struct v4l2_subdev_selection { __u32 target; __u32 flags; struct v4l2_rect r; - __u32 reserved[8]; + __u32 stream; + __u32 reserved[7]; }; /** @@ -175,6 +190,49 @@ struct v4l2_subdev_capability { /* The v4l2 sub-device video device node is registered in read-only mode. */ #define V4L2_SUBDEV_CAP_RO_SUBDEV 0x00000001 +/* The v4l2 sub-device supports routing and multiplexed streams. */ +#define V4L2_SUBDEV_CAP_STREAMS 0x00000002 + +/* + * Is the route active? An active route will start when streaming is enabled + * on a video node. + */ +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE (1U << 0) + +/** + * struct v4l2_subdev_route - A route inside a subdev + * + * @sink_pad: the sink pad index + * @sink_stream: the sink stream identifier + * @source_pad: the source pad index + * @source_stream: the source stream identifier + * @flags: route flags V4L2_SUBDEV_ROUTE_FL_* + * @reserved: drivers and applications must zero this array + */ +struct v4l2_subdev_route { + __u32 sink_pad; + __u32 sink_stream; + __u32 source_pad; + __u32 source_stream; + __u32 flags; + __u32 reserved[5]; +}; + +/** + * struct v4l2_subdev_routing - Subdev routing information + * + * @which: configuration type (from enum v4l2_subdev_format_whence) + * @num_routes: the total number of routes in the routes array + * @routes: pointer to the routes array + * @reserved: drivers and applications must zero this array + */ +struct v4l2_subdev_routing { + __u32 which; + __u32 num_routes; + __u64 routes; + __u32 reserved[6]; +}; + /* Backwards compatibility define --- to be removed */ #define v4l2_subdev_edid v4l2_edid @@ -190,6 +248,8 @@ struct v4l2_subdev_capability { #define VIDIOC_SUBDEV_S_CROP _IOWR('V', 60, struct v4l2_subdev_crop) #define VIDIOC_SUBDEV_G_SELECTION _IOWR('V', 61, struct v4l2_subdev_selection) #define VIDIOC_SUBDEV_S_SELECTION _IOWR('V', 62, struct v4l2_subdev_selection) +#define VIDIOC_SUBDEV_G_ROUTING _IOWR('V', 38, struct v4l2_subdev_routing) +#define VIDIOC_SUBDEV_S_ROUTING _IOWR('V', 39, struct v4l2_subdev_routing) /* The following ioctls are identical to the ioctls in videodev2.h */ #define VIDIOC_SUBDEV_G_STD _IOR('V', 23, v4l2_std_id) #define VIDIOC_SUBDEV_S_STD _IOW('V', 24, v4l2_std_id) |