Pull media updates from Mauro Carvalho Chehab: - Removal of some old unused sensor drivers: ad9389b, m5mols, mt9m032, mt9t001, noon010pc30, s5k6aa, sr030pc30 and vs6624 - New i.MX8 image sensor interface driver - Some new RC keymaps - lots of cleanups at atomisp driver to make it support standard features present on other webcam drivers - the cx18 and saa7146 now uses VB2 - lots of cleanups and driver improvements * tag 'media/v6.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (460 commits) media: ov5670: Fix probe on ACPI media: nxp: imx8-isi: Remove 300ms sleep after enabling channel media: nxp: imx8-isi: Replace udelay() with fsleep() media: nxp: imx8-isi: Drop partial support for i.MX8QM and i.MX8QXP media: nxp: Add i.MX8 ISI driver media: dt-bindings: media: Add i.MX8 ISI DT bindings media: atomisp: gmin_platform: Add Lenovo Ideapad Miix 310 gmin_vars media: atomisp: gmin_platform: Make DMI quirks take precedence over the _DSM table media: atomisp: Remove struct atomisp_sub_device index field media: atomisp: Drop support for streaming from 2 sensors at once media: atomisp: Remove atomisp_try_fmt() call from atomisp_set_fmt() media: atomisp: Remove unused ATOM_ISP_MAX_WIDTH_TMP and ATOM_ISP_MAX_HEIGHT_TMP media: atomisp: Remove snr_mbus_fmt local var from atomisp_try_fmt() media: atomisp: Remove custom V4L2_CID_FMT_AUTO control media: atomisp: Remove continuous mode related code from atomisp_set_fmt() media: atomisp: Remove duplicate atomisp_[start|stop]_streaming() prototypes media: atomisp: gc0310: Switch over to ACPI powermanagement media: atomisp: gc0310: Use devm_kzalloc() for data struct media: atomisp: gc0310: Add runtime-pm support media: atomisp: gc0310: Delay power-on till streaming is started ...
Unified · Split
| @@ -55,6 +55,15 @@ Miscellaneous: · 54 unmodified lines | ||
| 55 | 55 | you can control the CEC line through this driver. This supports error |
| 56 | 56 | injection as well. |
| 57 | 57 | |
| 58 | +- cec-gpio and Allwinner A10 (or any other driver that uses the CEC pin | |
| 59 | + framework to drive the CEC pin directly): the CEC pin framework uses | |
| 60 | + high-resolution timers. These timers are affected by NTP daemons that | |
| 61 | + speed up or slow down the clock to sync with the official time. The | |
| 62 | + chronyd server will by default increase or decrease the clock by | |
| 63 | + 1/12th. This will cause the CEC timings to go out of spec. To fix this, | |
| 64 | + add a 'maxslewrate 40000' line to chronyd.conf. This limits the clock | |
| 65 | + frequency change to 1/25th, which keeps the CEC timings within spec. | |
| 66 | + | |
| 58 | 67 | |
| 59 | 68 | Utilities |
| 60 | 69 | ========= |
| @@ -296,69 +305,71 @@ broadcast messages twice to reduce the chance of them being lost. Specifically · 235 unmodified lines | ||
| 296 | 305 | Making a CEC debugger |
| 297 | 306 | ===================== |
| 298 | 307 | |
| 299 | −By using a Raspberry Pi 2B/3/4 and some cheap components you can make | |
| 308 | +By using a Raspberry Pi 4B and some cheap components you can make | |
| 300 | 309 | your own low-level CEC debugger. |
| 301 | 310 | |
| 302 | −Here is a picture of my setup: | |
| 303 | − | |
| 304 | −https://hverkuil.home.xs4all.nl/rpi3-cec.jpg | |
| 305 | − | |
| 306 | −It's a Raspberry Pi 3 together with a breadboard and some breadboard wires: | |
| 307 | − | |
| 308 | −http://www.dx.com/p/diy-40p-male-to-female-male-to-male-female-to-female-dupont-line-wire-3pcs-356089#.WYLOOXWGN7I | |
| 309 | − | |
| 310 | −Finally on of these HDMI female-female passthrough connectors (full soldering type 1): | |
| 311 | +The critical component is one of these HDMI female-female passthrough connectors | |
| 312 | +(full soldering type 1): | |
| 311 | 313 | |
| 312 | 314 | https://elabbay.myshopify.com/collections/camera/products/hdmi-af-af-v1a-hdmi-type-a-female-to-hdmi-type-a-female-pass-through-adapter-breakout-board?variant=45533926147 |
| 313 | 315 | |
| 314 | −We've tested this and it works up to 4kp30 (297 MHz). The quality is not high | |
| 315 | −enough to pass-through 4kp60 (594 MHz). | |
| 316 | − | |
| 317 | −I also added an RTC and a breakout shield: | |
| 318 | − | |
| 319 | −https://www.amazon.com/Makerfire%C2%AE-Raspberry-Module-DS1307-Battery/dp/B00ZOXWHK4 | |
| 316 | +The video quality is variable and certainly not enough to pass-through 4kp60 | |
| 317 | +(594 MHz) video. You might be able to support 4kp30, but more likely you will | |
| 318 | +be limited to 1080p60 (148.5 MHz). But for CEC testing that is fine. | |
| 320 | 319 | |
| 321 | −https://www.dx.com/p/raspberry-pi-gpio-expansion-board-breadboard-easy-multiplexing-board-one-to-three-with-screw-for-raspberry-pi-2-3-b-b-2729992.html#.YGRCG0MzZ7I | |
| 320 | +You need a breadboard and some breadboard wires: | |
| 322 | 321 | |
| 323 | −These two are not needed but they make life a bit easier. | |
| 322 | +http://www.dx.com/p/diy-40p-male-to-female-male-to-male-female-to-female-dupont-line-wire-3pcs-356089#.WYLOOXWGN7I | |
| 324 | 323 | |
| 325 | −If you want to monitor the HPD line as well, then you need one of these | |
| 326 | −level shifters: | |
| 324 | +If you want to monitor the HPD and/or 5V lines as well, then you need one of | |
| 325 | +these 5V to 3.3V level shifters: | |
| 327 | 326 | |
| 328 | 327 | https://www.adafruit.com/product/757 |
| 329 | 328 | |
| 330 | 329 | (This is just where I got these components, there are many other places you |
| 331 | 330 | can get similar things). |
| 332 | 331 | |
| 332 | +The ground pin of the HDMI connector needs to be connected to a ground | |
| 333 | +pin of the Raspberry Pi, of course. | |
| 334 | + | |
| 333 | 335 | The CEC pin of the HDMI connector needs to be connected to these pins: |
| 334 | −CE0/IO8 and CE1/IO7 (pull-up GPIOs). The (optional) HPD pin of the HDMI | |
| 335 | −connector should be connected (via a level shifter to convert the 5V | |
| 336 | −to 3.3V) to these pins: IO17 and IO27. The (optional) 5V pin of the HDMI | |
| 337 | −connector should be connected (via a level shifter) to these pins: IO22 | |
| 338 | −and IO24. Monitoring the HPD an 5V lines is not necessary, but it is helpful. | |
| 336 | +GPIO 6 and GPIO 7. The optional HPD pin of the HDMI connector should | |
| 337 | +be connected via the level shifter to these pins: GPIO 23 and GPIO 12. | |
| 338 | +The optional 5V pin of the HDMI connector should be connected via the | |
| 339 | +level shifter to these pins: GPIO 25 and GPIO 22. Monitoring the HPD and | |
| 340 | +5V lines is not necessary, but it is helpful. | |
| 339 | 341 | |
| 340 | −This kernel patch will hook up the cec-gpio driver correctly to | |
| 341 | −e.g. ``arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts``:: | |
| 342 | +This device tree addition in ``arch/arm/boot/dts/bcm2711-rpi-4-b.dts`` | |
| 343 | +will hook up the cec-gpio driver correctly:: | |
| 344 | + | |
| 345 | + cec@6 { | |
| 346 | + compatible = "cec-gpio"; | |
| 347 | + cec-gpios = <&gpio 6 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; | |
| 348 | + hpd-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; | |
| 349 | + v5-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>; | |
| 350 | + }; | |
| 342 | 351 | |
| 343 | 352 | cec@7 { |
| 344 | 353 | compatible = "cec-gpio"; |
| 345 | 354 | cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; |
| 346 | − hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; | |
| 355 | + hpd-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; | |
| 347 | 356 | v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; |
| 348 | 357 | }; |
| 349 | 358 | |
| 350 | − cec@8 { | |
| 351 | − compatible = "cec-gpio"; | |
| 352 | − cec-gpios = <&gpio 8 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; | |
| 353 | − hpd-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; | |
| 354 | − v5-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; | |
| 355 | − }; | |
| 359 | +If you haven't hooked up the HPD and/or 5V lines, then just delete those | |
| 360 | +lines. | |
| 356 | 361 | |
| 357 | 362 | This dts change will enable two cec GPIO devices: I typically use one to |
| 358 | 363 | send/receive CEC commands and the other to monitor. If you monitor using |
| 359 | 364 | an unconfigured CEC adapter then it will use GPIO interrupts which makes |
| 360 | 365 | monitoring very accurate. |
| 361 | 366 | |
| 367 | +If you just want to monitor traffic, then a single instance is sufficient. | |
| 368 | +The minimum configuration is one HDMI female-female passthrough connector | |
| 369 | +and two female-female breadboard wires: one for connecting the HDMI ground | |
| 370 | +pin to a ground pin on the Raspberry Pi, and the other to connect the HDMI | |
| 371 | +CEC pin to GPIO 6 on the Raspberry Pi. | |
| 372 | + | |
| 362 | 373 | The documentation on how to use the error injection is here: :ref:`cec_pin_error_inj`. |
| 363 | 374 | |
| 364 | 375 | ``cec-ctl --monitor-pin`` will do low-level CEC bus sniffing and analysis. |
| @@ -72,17 +72,13 @@ imx319 Sony IMX319 sensor · 71 unmodified lines | ||
| 72 | 72 | imx334 Sony IMX334 sensor |
| 73 | 73 | imx355 Sony IMX355 sensor |
| 74 | 74 | imx412 Sony IMX412 sensor |
| 75 | −m5mols Fujitsu M-5MOLS 8MP sensor | |
| 76 | 75 | mt9m001 mt9m001 |
| 77 | −mt9m032 MT9M032 camera sensor | |
| 78 | 76 | mt9m111 mt9m111, mt9m112 and mt9m131 |
| 79 | 77 | mt9p031 Aptina MT9P031 |
| 80 | −mt9t001 Aptina MT9T001 | |
| 81 | 78 | mt9t112 Aptina MT9T111/MT9T112 |
| 82 | 79 | mt9v011 Micron mt9v011 sensor |
| 83 | 80 | mt9v032 Micron MT9V032 sensor |
| 84 | 81 | mt9v111 Aptina MT9V111 sensor |
| 85 | −noon010pc30 Siliconfile NOON010PC30 sensor | |
| 86 | 82 | ov13858 OmniVision OV13858 sensor |
| 87 | 83 | ov13b10 OmniVision OV13B10 sensor |
| 88 | 84 | ov2640 OmniVision OV2640 sensor |
| @@ -109,9 +105,6 @@ s5c73m3 Samsung S5C73M3 sensor · 20 unmodified lines | ||
| 109 | 105 | s5k4ecgx Samsung S5K4ECGX sensor |
| 110 | 106 | s5k5baf Samsung S5K5BAF sensor |
| 111 | 107 | s5k6a3 Samsung S5K6A3 sensor |
| 112 | −s5k6aa Samsung S5K6AAFX sensor | |
| 113 | −sr030pc30 Siliconfile SR030PC30 sensor | |
| 114 | −vs6624 ST VS6624 sensor | |
| 115 | 108 | ============ ========================================================== |
| 116 | 109 | |
| 117 | 110 | Flash devices |
| @@ -222,7 +215,6 @@ Video encoders · 104 unmodified lines | ||
| 222 | 215 | ============ ========================================================== |
| 223 | 216 | Driver Name |
| 224 | 217 | ============ ========================================================== |
| 225 | −ad9389b Analog Devices AD9389B encoder | |
| 226 | 218 | adv7170 Analog Devices ADV7170 video encoder |
| 227 | 219 | adv7175 Analog Devices ADV7175 video encoder |
| 228 | 220 | adv7343 ADV7343 video encoder |
| @@ -11,7 +11,7 @@ maintainers: · 10 unmodified lines | ||
| 11 | 11 | - Maxime Ripard <mripard@kernel.org> |
| 12 | 12 | |
| 13 | 13 | allOf: |
| 14 | − - $ref: "rc.yaml#" | |
| 14 | + - $ref: rc.yaml# | |
| 15 | 15 | |
| 16 | 16 | properties: |
| 17 | 17 | compatible: |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/allwinner,sun50i-h6-vpu-g2.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/allwinner,sun50i-h6-vpu-g2.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Hantro G2 VPU codec implemented on Allwinner H6 SoC |
| 9 | 9 | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | # Copyright 2020 BayLibre, SAS |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/amlogic,axg-ge2d.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/amlogic,axg-ge2d.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Amlogic GE2D Acceleration Unit |
| 9 | 9 | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | # Copyright 2019 BayLibre, SAS |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/amlogic,gx-vdec.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/amlogic,gx-vdec.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Amlogic Video Decoder |
| 9 | 9 | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/amlogic,meson-ir-tx.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/amlogic,meson-ir-tx.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Amlogic Meson IR transmitter |
| 9 | 9 | |
| @@ -0,0 +1,47 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/amlogic,meson6-ir.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Amlogic Meson IR remote control receiver | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Neil Armstrong <neil.armstrong@linaro.org> | |
| 11 | + | |
| 12 | +allOf: | |
| 13 | + - $ref: rc.yaml# | |
| 14 | + | |
| 15 | +properties: | |
| 16 | + compatible: | |
| 17 | + oneOf: | |
| 18 | + - enum: | |
| 19 | + - amlogic,meson6-ir | |
| 20 | + - amlogic,meson8b-ir | |
| 21 | + - amlogic,meson-gxbb-ir | |
| 22 | + - items: | |
| 23 | + - const: amlogic,meson-gx-ir | |
| 24 | + - const: amlogic,meson-gxbb-ir | |
| 25 | + | |
| 26 | + reg: | |
| 27 | + maxItems: 1 | |
| 28 | + | |
| 29 | + interrupts: | |
| 30 | + maxItems: 1 | |
| 31 | + | |
| 32 | +required: | |
| 33 | + - compatible | |
| 34 | + - reg | |
| 35 | + - interrupts | |
| 36 | + | |
| 37 | +unevaluatedProperties: false | |
| 38 | + | |
| 39 | +examples: | |
| 40 | + - | | |
| 41 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 42 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 43 | + ir-receiver@c8100480 { | |
| 44 | + compatible = "amlogic,meson6-ir"; | |
| 45 | + reg = <0xc8100480 0x20>; | |
| 46 | + interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>; | |
| 47 | + }; | |
| @@ -1,16 +0,0 @@ | ||
| 1 | −Exynos4x12/Exynos5 SoC series camera host interface (FIMC-LITE) | |
| 2 | − | |
| 3 | −Required properties: | |
| 4 | − | |
| 5 | −- compatible : should be one of: | |
| 6 | − "samsung,exynos4212-fimc-lite" for Exynos4212/4412 SoCs, | |
| 7 | − "samsung,exynos5250-fimc-lite" for Exynos5250 compatible | |
| 8 | − devices; | |
| 9 | −- reg : physical base address and size of the device memory mapped | |
| 10 | − registers; | |
| 11 | −- interrupts : should contain FIMC-LITE interrupt; | |
| 12 | −- clocks : FIMC LITE gate clock should be specified in this property. | |
| 13 | −- clock-names : should contain "flite" entry. | |
| 14 | − | |
| 15 | −Each FIMC device should have an alias in the aliases node, in the form of | |
| 16 | −fimc-lite<n>, where <n> is an integer specifying the IP block instance. | |
| @@ -1,50 +0,0 @@ | ||
| 1 | −Exynos4x12 SoC series Imaging Subsystem (FIMC-IS) | |
| 2 | − | |
| 3 | −The FIMC-IS is a subsystem for processing image signal from an image sensor. | |
| 4 | −The Exynos4x12 SoC series FIMC-IS V1.5 comprises of a dedicated ARM Cortex-A5 | |
| 5 | −processor, ISP, DRC and FD IP blocks and peripheral devices such as UART, I2C | |
| 6 | −and SPI bus controllers, PWM and ADC. | |
| 7 | − | |
| 8 | −fimc-is node | |
| 9 | −------------ | |
| 10 | − | |
| 11 | −Required properties: | |
| 12 | −- compatible : should be "samsung,exynos4212-fimc-is" for Exynos4212 and | |
| 13 | − Exynos4412 SoCs; | |
| 14 | −- reg : physical base address and length of the registers set; | |
| 15 | −- interrupts : must contain two FIMC-IS interrupts, in order: ISP0, ISP1; | |
| 16 | −- clocks : list of clock specifiers, corresponding to entries in | |
| 17 | − clock-names property; | |
| 18 | −- clock-names : must contain "ppmuispx", "ppmuispx", "lite0", "lite1" | |
| 19 | − "mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "gicisp", | |
| 20 | − "pwm_isp", "mcuctl_isp", "uart", "ispdiv0", "ispdiv1", | |
| 21 | − "mcuispdiv0", "mcuispdiv1", "aclk200", "div_aclk200", | |
| 22 | − "aclk400mcuisp", "div_aclk400mcuisp" entries, | |
| 23 | − matching entries in the clocks property. | |
| 24 | −pmu subnode | |
| 25 | −----------- | |
| 26 | − | |
| 27 | −Required properties: | |
| 28 | − - reg : must contain PMU physical base address and size of the register set. | |
| 29 | − | |
| 30 | −The following are the FIMC-IS peripheral device nodes and can be specified | |
| 31 | −either standalone or as the fimc-is node child nodes. | |
| 32 | − | |
| 33 | −i2c-isp (ISP I2C bus controller) nodes | |
| 34 | −------------------------------------------ | |
| 35 | − | |
| 36 | −Required properties: | |
| 37 | − | |
| 38 | −- compatible : should be "samsung,exynos4212-i2c-isp" for Exynos4212 and | |
| 39 | − Exynos4412 SoCs; | |
| 40 | −- reg : physical base address and length of the registers set; | |
| 41 | −- clocks : must contain gate clock specifier for this controller; | |
| 42 | −- clock-names : must contain "i2c_isp" entry. | |
| 43 | − | |
| 44 | −For the above nodes it is required to specify a pinctrl state named "default", | |
| 45 | −according to the pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt. | |
| 46 | − | |
| 47 | −Device tree nodes of the image sensors' controlled directly by the FIMC-IS | |
| 48 | −firmware must be child nodes of their corresponding ISP I2C bus controller node. | |
| 49 | −The data link of these image sensors must be specified using the common video | |
| 50 | −interfaces bindings, defined in video-interfaces.txt. | |
| @@ -23,6 +23,9 @@ properties: · 22 unmodified lines | ||
| 23 | 23 | description: autosuspend delay time in milliseconds |
| 24 | 24 | $ref: /schemas/types.yaml#/definitions/uint32 |
| 25 | 25 | |
| 26 | + wakeup-source: | |
| 27 | + description: IR receiver can wake-up the system. | |
| 28 | + | |
| 26 | 29 | required: |
| 27 | 30 | - compatible |
| 28 | 31 | - gpios |
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
| 2 | 2 | %YAML 1.2 |
| 3 | 3 | --- |
| 4 | −$id: "http://devicetree.org/schemas/media/i2c/chrontel,ch7322.yaml#" | |
| 5 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/i2c/chrontel,ch7322.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | 6 | |
| 7 | 7 | title: Chrontel HDMI-CEC Controller |
| 8 | 8 | |
| @@ -38,7 +38,7 @@ properties: · 37 unmodified lines | ||
| 38 | 38 | dongwoon,aac-mode: |
| 39 | 39 | description: |
| 40 | 40 | Indication of AAC mode select. |
| 41 | − $ref: "/schemas/types.yaml#/definitions/uint32" | |
| 41 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 42 | 42 | enum: |
| 43 | 43 | - 1 # AAC2 mode(operation time# 0.48 x Tvib) |
| 44 | 44 | - 2 # AAC3 mode(operation time# 0.70 x Tvib) |
| @@ -50,7 +50,7 @@ properties: · 5 unmodified lines | ||
| 50 | 50 | description: |
| 51 | 51 | Number of AAC Timing count that controlled by one 6-bit period of |
| 52 | 52 | vibration register AACT[5:0], the unit of which is 100 us. |
| 53 | − $ref: "/schemas/types.yaml#/definitions/uint32" | |
| 53 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 54 | 54 | default: 0x20 |
| 55 | 55 | minimum: 0x00 |
| 56 | 56 | maximum: 0x3f |
| @@ -59,7 +59,7 @@ properties: · 2 unmodified lines | ||
| 59 | 59 | description: |
| 60 | 60 | Indication of VCM internal clock dividing rate select, as one multiple |
| 61 | 61 | factor to calculate VCM ring periodic time Tvib. |
| 62 | − $ref: "/schemas/types.yaml#/definitions/uint32" | |
| 62 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 63 | 63 | enum: |
| 64 | 64 | - 0 # Dividing Rate - 2 |
| 65 | 65 | - 1 # Dividing Rate - 1 |
| @@ -86,7 +86,7 @@ properties: · 85 unmodified lines | ||
| 86 | 86 | is 100000 micro volts |
| 87 | 87 | |
| 88 | 88 | maxim,gpio-poc: |
| 89 | − $ref: '/schemas/types.yaml#/definitions/uint32-array' | |
| 89 | + $ref: /schemas/types.yaml#/definitions/uint32-array | |
| 90 | 90 | minItems: 2 |
| 91 | 91 | maxItems: 2 |
| 92 | 92 | description: | |
| @@ -1,41 +0,0 @@ | ||
| 1 | −* Omnivision OV2685 MIPI CSI-2 sensor | |
| 2 | − | |
| 3 | −Required Properties: | |
| 4 | −- compatible: shall be "ovti,ov2685" | |
| 5 | −- clocks: reference to the xvclk input clock | |
| 6 | −- clock-names: shall be "xvclk" | |
| 7 | −- avdd-supply: Analog voltage supply, 2.8 volts | |
| 8 | −- dovdd-supply: Digital I/O voltage supply, 1.8 volts | |
| 9 | −- dvdd-supply: Digital core voltage supply, 1.8 volts | |
| 10 | −- reset-gpios: Low active reset gpio | |
| 11 | − | |
| 12 | −The device node shall contain one 'port' child node with an | |
| 13 | −'endpoint' subnode for its digital output video port, | |
| 14 | −in accordance with the video interface bindings defined in | |
| 15 | −Documentation/devicetree/bindings/media/video-interfaces.txt. | |
| 16 | −The endpoint optional property 'data-lanes' shall be "<1>". | |
| 17 | − | |
| 18 | −Example: | |
| 19 | −&i2c7 { | |
| 20 | − ov2685: camera-sensor@3c { | |
| 21 | − compatible = "ovti,ov2685"; | |
| 22 | − reg = <0x3c>; | |
| 23 | − pinctrl-names = "default"; | |
| 24 | − pinctrl-0 = <&clk_24m_cam>; | |
| 25 | − | |
| 26 | − clocks = <&cru SCLK_TESTCLKOUT1>; | |
| 27 | − clock-names = "xvclk"; | |
| 28 | − | |
| 29 | − avdd-supply = <&pp2800_cam>; | |
| 30 | − dovdd-supply = <&pp1800>; | |
| 31 | − dvdd-supply = <&pp1800>; | |
| 32 | − reset-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; | |
| 33 | − | |
| 34 | − port { | |
| 35 | − ucam_out: endpoint { | |
| 36 | − remote-endpoint = <&mipi_in_ucam>; | |
| 37 | − data-lanes = <1>; | |
| 38 | − }; | |
| 39 | − }; | |
| 40 | − }; | |
| 41 | −}; | |
| @@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# · 7 unmodified lines | ||
| 8 | 8 | title: Omnivision OV8856 CMOS Sensor |
| 9 | 9 | |
| 10 | 10 | maintainers: |
| 11 | − - Dongchun Zhu <dongchun.zhu@mediatek.com> | |
| 11 | + - Sakari Ailus <sakari.ailus@linux.intel.com> | |
| 12 | 12 | |
| 13 | 13 | description: |- |
| 14 | 14 | The Omnivision OV8856 is a high performance, 1/4-inch, 8 megapixel, CMOS |
| @@ -88,7 +88,7 @@ properties: · 87 unmodified lines | ||
| 88 | 88 | properties: |
| 89 | 89 | link-frequencies: true |
| 90 | 90 | ovti,mipi-clock-voltage: |
| 91 | − $ref: "/schemas/types.yaml#/definitions/uint32" | |
| 91 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 92 | 92 | description: |
| 93 | 93 | Definition of MIPI clock voltage unit. This entry corresponds to |
| 94 | 94 | the link speed defined by the 'link-frequencies' property. |
| @@ -0,0 +1,101 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/i2c/ovti,ov2685.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: OmniVision OV2685 Image Sensor | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Shunqian Zheng <zhengsq@rock-chips.com> | |
| 11 | + | |
| 12 | +properties: | |
| 13 | + compatible: | |
| 14 | + const: ovti,ov2685 | |
| 15 | + | |
| 16 | + reg: | |
| 17 | + maxItems: 1 | |
| 18 | + | |
| 19 | + clocks: | |
| 20 | + items: | |
| 21 | + - description: XVCLK clock | |
| 22 | + | |
| 23 | + clock-names: | |
| 24 | + items: | |
| 25 | + - const: xvclk | |
| 26 | + | |
| 27 | + dvdd-supply: | |
| 28 | + description: Digital Domain Power Supply | |
| 29 | + | |
| 30 | + avdd-supply: | |
| 31 | + description: Analog Domain Power Supply | |
| 32 | + | |
| 33 | + dovdd-supply: | |
| 34 | + description: I/O Domain Power Supply | |
| 35 | + | |
| 36 | + reset-gpios: | |
| 37 | + maxItems: 1 | |
| 38 | + description: Reset Pin GPIO Control (active low) | |
| 39 | + | |
| 40 | + port: | |
| 41 | + description: MIPI CSI-2 transmitter port | |
| 42 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 43 | + additionalProperties: false | |
| 44 | + | |
| 45 | + properties: | |
| 46 | + endpoint: | |
| 47 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 48 | + unevaluatedProperties: false | |
| 49 | + | |
| 50 | + properties: | |
| 51 | + data-lanes: | |
| 52 | + maxItems: 2 | |
| 53 | + | |
| 54 | + required: | |
| 55 | + - data-lanes | |
| 56 | + | |
| 57 | +required: | |
| 58 | + - compatible | |
| 59 | + - reg | |
| 60 | + - clocks | |
| 61 | + - clock-names | |
| 62 | + - dvdd-supply | |
| 63 | + - avdd-supply | |
| 64 | + - dovdd-supply | |
| 65 | + - port | |
| 66 | + | |
| 67 | +additionalProperties: false | |
| 68 | + | |
| 69 | +examples: | |
| 70 | + - | | |
| 71 | + #include <dt-bindings/clock/rk3399-cru.h> | |
| 72 | + #include <dt-bindings/gpio/gpio.h> | |
| 73 | + | |
| 74 | + i2c { | |
| 75 | + #address-cells = <1>; | |
| 76 | + #size-cells = <0>; | |
| 77 | + | |
| 78 | + ov2685: camera-sensor@3c { | |
| 79 | + compatible = "ovti,ov2685"; | |
| 80 | + reg = <0x3c>; | |
| 81 | + pinctrl-names = "default"; | |
| 82 | + pinctrl-0 = <&clk_24m_cam>; | |
| 83 | + | |
| 84 | + clocks = <&cru SCLK_TESTCLKOUT1>; | |
| 85 | + clock-names = "xvclk"; | |
| 86 | + | |
| 87 | + avdd-supply = <&pp2800_cam>; | |
| 88 | + dovdd-supply = <&pp1800>; | |
| 89 | + dvdd-supply = <&pp1800>; | |
| 90 | + reset-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; | |
| 91 | + | |
| 92 | + port { | |
| 93 | + ucam_out: endpoint { | |
| 94 | + remote-endpoint = <&mipi_in_ucam>; | |
| 95 | + data-lanes = <1>; | |
| 96 | + }; | |
| 97 | + }; | |
| 98 | + }; | |
| 99 | + }; | |
| 100 | + | |
| 101 | +... | |
| @@ -0,0 +1,101 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/i2c/samsung,s5k5baf.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor with embedded SoC ISP | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + | |
| 12 | +properties: | |
| 13 | + compatible: | |
| 14 | + const: samsung,s5k5baf | |
| 15 | + | |
| 16 | + reg: | |
| 17 | + maxItems: 1 | |
| 18 | + | |
| 19 | + clocks: | |
| 20 | + maxItems: 1 | |
| 21 | + | |
| 22 | + clock-names: | |
| 23 | + items: | |
| 24 | + - const: mclk | |
| 25 | + | |
| 26 | + clock-frequency: | |
| 27 | + default: 24000000 | |
| 28 | + description: mclk clock frequency | |
| 29 | + | |
| 30 | + rstn-gpios: | |
| 31 | + maxItems: 1 | |
| 32 | + description: RSTN pin | |
| 33 | + | |
| 34 | + stbyn-gpios: | |
| 35 | + maxItems: 1 | |
| 36 | + description: STDBYN pin | |
| 37 | + | |
| 38 | + vdda-supply: | |
| 39 | + description: Analog power supply 2.8V (2.6V to 3.0V) | |
| 40 | + | |
| 41 | + vddio-supply: | |
| 42 | + description: I/O power supply 1.8V (1.65V to 1.95V) or 2.8V (2.5V to 3.1V) | |
| 43 | + | |
| 44 | + vddreg-supply: | |
| 45 | + description: | |
| 46 | + Regulator input power supply 1.8V (1.7V to 1.9V) or 2.8V (2.6V to 3.0) | |
| 47 | + | |
| 48 | + port: | |
| 49 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 50 | + additionalProperties: false | |
| 51 | + | |
| 52 | + properties: | |
| 53 | + endpoint: | |
| 54 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 55 | + unevaluatedProperties: false | |
| 56 | + | |
| 57 | + properties: | |
| 58 | + data-lanes: | |
| 59 | + items: | |
| 60 | + - const: 1 | |
| 61 | + | |
| 62 | +required: | |
| 63 | + - compatible | |
| 64 | + - clocks | |
| 65 | + - clock-names | |
| 66 | + - rstn-gpios | |
| 67 | + - stbyn-gpios | |
| 68 | + - vdda-supply | |
| 69 | + - vddio-supply | |
| 70 | + - vddreg-supply | |
| 71 | + | |
| 72 | +additionalProperties: false | |
| 73 | + | |
| 74 | +examples: | |
| 75 | + - | | |
| 76 | + #include <dt-bindings/gpio/gpio.h> | |
| 77 | + | |
| 78 | + i2c { | |
| 79 | + #address-cells = <1>; | |
| 80 | + #size-cells = <0>; | |
| 81 | + | |
| 82 | + sensor@2d { | |
| 83 | + compatible = "samsung,s5k5baf"; | |
| 84 | + reg = <0x2d>; | |
| 85 | + clocks = <&camera 0>; | |
| 86 | + clock-names = "mclk"; | |
| 87 | + clock-frequency = <24000000>; | |
| 88 | + rstn-gpios = <&gpl2 1 GPIO_ACTIVE_LOW>; | |
| 89 | + stbyn-gpios = <&gpl2 0 GPIO_ACTIVE_LOW>; | |
| 90 | + vdda-supply = <&cam_io_en_reg>; | |
| 91 | + vddio-supply = <&vtcam_reg>; | |
| 92 | + vddreg-supply = <&vt_core_15v_reg>; | |
| 93 | + | |
| 94 | + port { | |
| 95 | + endpoint { | |
| 96 | + remote-endpoint = <&csis1_ep>; | |
| 97 | + data-lanes = <1>; | |
| 98 | + }; | |
| 99 | + }; | |
| 100 | + }; | |
| 101 | + }; | |
| @@ -0,0 +1,98 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/i2c/samsung,s5k6a3.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung S5K6A3(YX) raw image sensor | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + | |
| 12 | +description: | |
| 13 | + S5K6A3(YX) is a raw image sensor with MIPI CSI-2 and CCP2 image data | |
| 14 | + interfaces and CCI (I2C compatible) control bus. | |
| 15 | + | |
| 16 | +properties: | |
| 17 | + compatible: | |
| 18 | + const: samsung,s5k6a3 | |
| 19 | + | |
| 20 | + reg: | |
| 21 | + maxItems: 1 | |
| 22 | + | |
| 23 | + clocks: | |
| 24 | + maxItems: 1 | |
| 25 | + | |
| 26 | + clock-names: | |
| 27 | + items: | |
| 28 | + - const: extclk | |
| 29 | + | |
| 30 | + clock-frequency: | |
| 31 | + default: 24000000 | |
| 32 | + description: extclk clock frequency | |
| 33 | + | |
| 34 | + gpios: | |
| 35 | + maxItems: 1 | |
| 36 | + description: GPIO connected to the RESET pin | |
| 37 | + | |
| 38 | + afvdd-supply: | |
| 39 | + description: AF (actuator) voltage supply | |
| 40 | + | |
| 41 | + svdda-supply: | |
| 42 | + description: Core voltage supply | |
| 43 | + | |
| 44 | + svddio-supply: | |
| 45 | + description: I/O voltage supply | |
| 46 | + | |
| 47 | + port: | |
| 48 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 49 | + additionalProperties: false | |
| 50 | + | |
| 51 | + properties: | |
| 52 | + endpoint: | |
| 53 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 54 | + unevaluatedProperties: false | |
| 55 | + | |
| 56 | + properties: | |
| 57 | + data-lanes: | |
| 58 | + items: | |
| 59 | + - const: 1 | |
| 60 | + | |
| 61 | +required: | |
| 62 | + - compatible | |
| 63 | + - clocks | |
| 64 | + - clock-names | |
| 65 | + - gpios | |
| 66 | + - afvdd-supply | |
| 67 | + - svdda-supply | |
| 68 | + - svddio-supply | |
| 69 | + | |
| 70 | +additionalProperties: false | |
| 71 | + | |
| 72 | +examples: | |
| 73 | + - | | |
| 74 | + #include <dt-bindings/gpio/gpio.h> | |
| 75 | + | |
| 76 | + i2c { | |
| 77 | + #address-cells = <1>; | |
| 78 | + #size-cells = <0>; | |
| 79 | + | |
| 80 | + sensor@10 { | |
| 81 | + compatible = "samsung,s5k6a3"; | |
| 82 | + reg = <0x10>; | |
| 83 | + clock-frequency = <24000000>; | |
| 84 | + clocks = <&camera 1>; | |
| 85 | + clock-names = "extclk"; | |
| 86 | + gpios = <&gpm1 6 GPIO_ACTIVE_LOW>; | |
| 87 | + afvdd-supply = <&ldo19_reg>; | |
| 88 | + svdda-supply = <&cam_io_reg>; | |
| 89 | + svddio-supply = <&ldo19_reg>; | |
| 90 | + | |
| 91 | + port { | |
| 92 | + endpoint { | |
| 93 | + remote-endpoint = <&csis1_ep>; | |
| 94 | + data-lanes = <1>; | |
| 95 | + }; | |
| 96 | + }; | |
| 97 | + }; | |
| 98 | + }; | |
| @@ -12,15 +12,26 @@ maintainers: · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | description: |- |
| 14 | 14 | The Sony IMX290 is a 1/2.8-Inch CMOS Solid-state image sensor with Square |
| 15 | − Pixel for Color Cameras. It is programmable through I2C and 4-wire | |
| 16 | − interfaces. The sensor output is available via CMOS logic parallel SDR | |
| 17 | − output, Low voltage LVDS DDR output and CSI-2 serial data output. The CSI-2 | |
| 18 | − bus is the default. No bindings have been defined for the other busses. | |
| 15 | + Pixel, available in either mono or colour variants. It is programmable | |
| 16 | + through I2C and 4-wire interfaces. | |
| 17 | + | |
| 18 | + The sensor output is available via CMOS logic parallel SDR output, Low voltage | |
| 19 | + LVDS DDR output and CSI-2 serial data output. The CSI-2 bus is the default. | |
| 20 | + No bindings have been defined for the other busses. | |
| 21 | + | |
| 22 | + imx290lqr is the full model identifier for the colour variant. "sony,imx290" | |
| 23 | + is treated the same as this as it was the original compatible string. | |
| 24 | + imx290llr is the mono version of the sensor. | |
| 19 | 25 | |
| 20 | 26 | properties: |
| 21 | 27 | compatible: |
| 22 | − enum: | |
| 23 | − - sony,imx290 | |
| 28 | + oneOf: | |
| 29 | + - enum: | |
| 30 | + - sony,imx290lqr # Colour | |
| 31 | + - sony,imx290llr # Monochrome | |
| 32 | + - sony,imx327lqr # Colour | |
| 33 | + - const: sony,imx290 | |
| 34 | + deprecated: true | |
| 24 | 35 | |
| 25 | 36 | reg: |
| 26 | 37 | maxItems: 1 |
| @@ -101,7 +112,7 @@ examples: · 74 unmodified lines | ||
| 101 | 112 | #size-cells = <0>; |
| 102 | 113 | |
| 103 | 114 | imx290: camera-sensor@1a { |
| 104 | − compatible = "sony,imx290"; | |
| 115 | + compatible = "sony,imx290lqr"; | |
| 105 | 116 | reg = <0x1a>; |
| 106 | 117 | |
| 107 | 118 | pinctrl-names = "default"; |
| @@ -82,7 +82,7 @@ examples: · 81 unmodified lines | ||
| 82 | 82 | imx334: endpoint { |
| 83 | 83 | remote-endpoint = <&cam>; |
| 84 | 84 | data-lanes = <1 2 3 4>; |
| 85 | − link-frequencies = /bits/ 64 <891000000>; | |
| 85 | + link-frequencies = /bits/ 64 <891000000 445500000>; | |
| 86 | 86 | }; |
| 87 | 87 | }; |
| 88 | 88 | }; |
| @@ -27,7 +27,7 @@ properties: · 26 unmodified lines | ||
| 27 | 27 | maxItems: 1 |
| 28 | 28 | |
| 29 | 29 | mediatek,gce-client-reg: |
| 30 | − $ref: '/schemas/types.yaml#/definitions/phandle-array' | |
| 30 | + $ref: /schemas/types.yaml#/definitions/phandle-array | |
| 31 | 31 | items: |
| 32 | 32 | items: |
| 33 | 33 | - description: phandle of GCE |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/mediatek,vcodec-subdev-decoder.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/mediatek,vcodec-subdev-decoder.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Mediatek Video Decode Accelerator With Multi Hardware |
| 9 | 9 | |
| @@ -61,7 +61,10 @@ properties: · 51 unmodified lines | ||
| 61 | 61 | - mediatek,mt8195-vcodec-dec |
| 62 | 62 | |
| 63 | 63 | reg: |
| 64 | − maxItems: 1 | |
| 64 | + minItems: 1 | |
| 65 | + items: | |
| 66 | + - description: VDEC_SYS register space | |
| 67 | + - description: VDEC_RACING_CTRL register space | |
| 65 | 68 | |
| 66 | 69 | iommus: |
| 67 | 70 | minItems: 1 |
| @@ -76,11 +79,6 @@ properties: · 8 unmodified lines | ||
| 76 | 79 | The node of system control processor (SCP), using |
| 77 | 80 | the remoteproc & rpmsg framework. |
| 78 | 81 | |
| 79 | − dma-ranges: | |
| 80 | − maxItems: 1 | |
| 81 | − description: | | |
| 82 | − Describes the physical address space of IOMMU maps to memory. | |
| 83 | − | |
| 84 | 82 | "#address-cells": |
| 85 | 83 | const: 2 |
| 86 | 84 | |
| @@ -91,17 +89,19 @@ properties: · 4 unmodified lines | ||
| 91 | 89 | |
| 92 | 90 | # Required child node: |
| 93 | 91 | patternProperties: |
| 94 | − '^vcodec-lat@[0-9a-f]+$': | |
| 92 | + '^video-codec@[0-9a-f]+$': | |
| 95 | 93 | type: object |
| 96 | 94 | |
| 97 | 95 | properties: |
| 98 | 96 | compatible: |
| 99 | 97 | enum: |
| 98 | + - mediatek,mtk-vcodec-core | |
| 100 | 99 | - mediatek,mtk-vcodec-lat |
| 101 | 100 | - mediatek,mtk-vcodec-lat-soc |
| 102 | 101 | |
| 103 | 102 | reg: |
| 104 | 103 | maxItems: 1 |
| 104 | + description: VDEC_MISC register space | |
| 105 | 105 | |
| 106 | 106 | interrupts: |
| 107 | 107 | maxItems: 1 |
| @@ -114,68 +114,13 @@ patternProperties: · 6 unmodified lines | ||
| 114 | 114 | Refer to bindings/iommu/mediatek,iommu.yaml. |
| 115 | 115 | |
| 116 | 116 | clocks: |
| 117 | + minItems: 4 | |
| 117 | 118 | maxItems: 5 |
| 118 | 119 | |
| 119 | 120 | clock-names: |
| 120 | − items: | |
| 121 | − - const: sel | |
| 122 | − - const: soc-vdec | |
| 123 | − - const: soc-lat | |
| 124 | − - const: vdec | |
| 125 | − - const: top | |
| 126 | − | |
| 127 | − assigned-clocks: | |
| 128 | − maxItems: 1 | |
| 129 | − | |
| 130 | − assigned-clock-parents: | |
| 131 | − maxItems: 1 | |
| 132 | − | |
| 133 | − power-domains: | |
| 134 | − maxItems: 1 | |
| 135 | − | |
| 136 | − required: | |
| 137 | − - compatible | |
| 138 | − - reg | |
| 139 | − - iommus | |
| 140 | − - clocks | |
| 141 | − - clock-names | |
| 142 | − - assigned-clocks | |
| 143 | − - assigned-clock-parents | |
| 144 | − - power-domains | |
| 145 | − | |
| 146 | − additionalProperties: false | |
| 147 | − | |
| 148 | − '^vcodec-core@[0-9a-f]+$': | |
| 149 | − type: object | |
| 150 | − | |
| 151 | − properties: | |
| 152 | − compatible: | |
| 153 | − const: mediatek,mtk-vcodec-core | |
| 154 | − | |
| 155 | − reg: | |
| 156 | − maxItems: 1 | |
| 157 | − | |
| 158 | − interrupts: | |
| 159 | − maxItems: 1 | |
| 160 | − | |
| 161 | − iommus: | |
| 162 | − minItems: 1 | |
| 163 | − maxItems: 32 | |
| 164 | − description: | | |
| 165 | − List of the hardware port in respective IOMMU block for current Socs. | |
| 166 | − Refer to bindings/iommu/mediatek,iommu.yaml. | |
| 167 | − | |
| 168 | − clocks: | |
| 121 | + minItems: 4 | |
| 169 | 122 | maxItems: 5 |
| 170 | 123 | |
| 171 | − clock-names: | |
| 172 | − items: | |
| 173 | − - const: sel | |
| 174 | − - const: soc-vdec | |
| 175 | − - const: soc-lat | |
| 176 | − - const: vdec | |
| 177 | − - const: top | |
| 178 | − | |
| 179 | 124 | assigned-clocks: |
| 180 | 125 | maxItems: 1 |
| 181 | 126 | |
| @@ -188,7 +133,6 @@ patternProperties: · 6 unmodified lines | ||
| 188 | 133 | required: |
| 189 | 134 | - compatible |
| 190 | 135 | - reg |
| 191 | − - interrupts | |
| 192 | 136 | - iommus |
| 193 | 137 | - clocks |
| 194 | 138 | - clock-names |
| @@ -203,7 +147,6 @@ required: · 8 unmodified lines | ||
| 203 | 147 | - reg |
| 204 | 148 | - iommus |
| 205 | 149 | - mediatek,scp |
| 206 | − - dma-ranges | |
| 207 | 150 | - ranges |
| 208 | 151 | |
| 209 | 152 | if: |
| @@ -211,12 +154,45 @@ if: · 1 unmodified line | ||
| 211 | 154 | compatible: |
| 212 | 155 | contains: |
| 213 | 156 | enum: |
| 157 | + - mediatek,mtk-vcodec-core | |
| 214 | 158 | - mediatek,mtk-vcodec-lat |
| 215 | 159 | |
| 216 | 160 | then: |
| 217 | 161 | required: |
| 218 | 162 | - interrupts |
| 219 | 163 | |
| 164 | +allOf: | |
| 165 | + - if: | |
| 166 | + properties: | |
| 167 | + compatible: | |
| 168 | + contains: | |
| 169 | + enum: | |
| 170 | + - mediatek,mt8192-vcodec-dec | |
| 171 | + then: | |
| 172 | + properties: | |
| 173 | + clock-names: | |
| 174 | + items: | |
| 175 | + - const: sel | |
| 176 | + - const: soc-vdec | |
| 177 | + - const: soc-lat | |
| 178 | + - const: vdec | |
| 179 | + - const: top | |
| 180 | + | |
| 181 | + - if: | |
| 182 | + properties: | |
| 183 | + compatible: | |
| 184 | + contains: | |
| 185 | + enum: | |
| 186 | + - mediatek,mt8195-vcodec-dec | |
| 187 | + then: | |
| 188 | + properties: | |
| 189 | + clock-names: | |
| 190 | + items: | |
| 191 | + - const: sel | |
| 192 | + - const: vdec | |
| 193 | + - const: lat | |
| 194 | + - const: top | |
| 195 | + | |
| 220 | 196 | additionalProperties: false |
| 221 | 197 | |
| 222 | 198 | examples: |
| @@ -236,12 +212,11 @@ examples: · 13 unmodified lines | ||
| 236 | 212 | compatible = "mediatek,mt8192-vcodec-dec"; |
| 237 | 213 | mediatek,scp = <&scp>; |
| 238 | 214 | iommus = <&iommu0 M4U_PORT_L4_VDEC_MC_EXT>; |
| 239 | − dma-ranges = <0x1 0x0 0x0 0x40000000 0x0 0xfff00000>; | |
| 240 | 215 | #address-cells = <2>; |
| 241 | 216 | #size-cells = <2>; |
| 242 | 217 | ranges = <0 0 0 0x16000000 0 0x40000>; |
| 243 | 218 | reg = <0 0x16000000 0 0x1000>; /* VDEC_SYS */ |
| 244 | − vcodec-lat@10000 { | |
| 219 | + video-codec@10000 { | |
| 245 | 220 | compatible = "mediatek,mtk-vcodec-lat"; |
| 246 | 221 | reg = <0 0x10000 0 0x800>; |
| 247 | 222 | interrupts = <GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH 0>; |
| @@ -264,7 +239,7 @@ examples: · 16 unmodified lines | ||
| 264 | 239 | power-domains = <&spm MT8192_POWER_DOMAIN_VDEC>; |
| 265 | 240 | }; |
| 266 | 241 | |
| 267 | − vcodec-core@25000 { | |
| 242 | + video-codec@25000 { | |
| 268 | 243 | compatible = "mediatek,mtk-vcodec-core"; |
| 269 | 244 | reg = <0 0x25000 0 0x1000>; |
| 270 | 245 | interrupts = <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH 0>; |
| @@ -1,20 +0,0 @@ | ||
| 1 | −* Amlogic Meson IR remote control receiver | |
| 2 | − | |
| 3 | −Required properties: | |
| 4 | − - compatible : depending on the platform this should be one of: | |
| 5 | − - "amlogic,meson6-ir" | |
| 6 | − - "amlogic,meson8b-ir" | |
| 7 | − - "amlogic,meson-gxbb-ir" | |
| 8 | − - reg : physical base address and length of the device registers | |
| 9 | − - interrupts : a single specifier for the interrupt from the device | |
| 10 | − | |
| 11 | −Optional properties: | |
| 12 | − - linux,rc-map-name: see rc.txt file in the same directory. | |
| 13 | − | |
| 14 | −Example: | |
| 15 | − | |
| 16 | − ir-receiver@c8100480 { | |
| 17 | − compatible= "amlogic,meson6-ir"; | |
| 18 | − reg = <0xc8100480 0x20>; | |
| 19 | − interrupts = <0 15 1>; | |
| 20 | − }; | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/microchip,sama5d4-vdec.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/microchip,sama5d4-vdec.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Hantro G1 VPU codec implemented on Microchip SAMA5D4 SoCs |
| 9 | 9 | |
| @@ -0,0 +1,173 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/nxp,imx8-isi.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: i.MX8 Image Sensing Interface | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
| 11 | + | |
| 12 | +description: | | |
| 13 | + The Image Sensing Interface (ISI) combines image processing pipelines with | |
| 14 | + DMA engines to process and capture frames originating from a variety of | |
| 15 | + sources. The inputs to the ISI go through Pixel Link interfaces, and their | |
| 16 | + number and nature is SoC-dependent. They cover both capture interfaces (MIPI | |
| 17 | + CSI-2 RX, HDMI RX, ...) and display engine outputs for writeback support. | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + enum: | |
| 22 | + - fsl,imx8mn-isi | |
| 23 | + - fsl,imx8mp-isi | |
| 24 | + | |
| 25 | + reg: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | + clocks: | |
| 29 | + items: | |
| 30 | + - description: The AXI clock | |
| 31 | + - description: The APB clock | |
| 32 | + # TODO: Check if the per-channel ipg_proc_clk clocks need to be specified | |
| 33 | + # as well, in case some SoCs have the ability to control them separately. | |
| 34 | + # This may be the case of the i.MX8[DQ]X(P) | |
| 35 | + | |
| 36 | + clock-names: | |
| 37 | + items: | |
| 38 | + - const: axi | |
| 39 | + - const: apb | |
| 40 | + | |
| 41 | + fsl,blk-ctrl: | |
| 42 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 43 | + description: | |
| 44 | + A phandle referencing the block control that contains the CSIS to ISI | |
| 45 | + gasket. | |
| 46 | + | |
| 47 | + interrupts: | |
| 48 | + description: Processing pipeline interrupts, one per pipeline | |
| 49 | + minItems: 1 | |
| 50 | + maxItems: 2 | |
| 51 | + | |
| 52 | + power-domains: | |
| 53 | + maxItems: 1 | |
| 54 | + | |
| 55 | + ports: | |
| 56 | + $ref: /schemas/graph.yaml#/properties/ports | |
| 57 | + description: | | |
| 58 | + Ports represent the Pixel Link inputs to the ISI. Their number and | |
| 59 | + assignment are model-dependent. Each port shall have a single endpoint. | |
| 60 | + | |
| 61 | +required: | |
| 62 | + - compatible | |
| 63 | + - reg | |
| 64 | + - interrupts | |
| 65 | + - clocks | |
| 66 | + - clock-names | |
| 67 | + - fsl,blk-ctrl | |
| 68 | + - ports | |
| 69 | + | |
| 70 | +allOf: | |
| 71 | + - if: | |
| 72 | + properties: | |
| 73 | + compatible: | |
| 74 | + contains: | |
| 75 | + const: fsl,imx8mn-isi | |
| 76 | + then: | |
| 77 | + properties: | |
| 78 | + interrupts: | |
| 79 | + maxItems: 1 | |
| 80 | + ports: | |
| 81 | + properties: | |
| 82 | + port@0: | |
| 83 | + description: MIPI CSI-2 RX | |
| 84 | + required: | |
| 85 | + - port@0 | |
| 86 | + | |
| 87 | + - if: | |
| 88 | + properties: | |
| 89 | + compatible: | |
| 90 | + contains: | |
| 91 | + const: fsl,imx8mp-isi | |
| 92 | + then: | |
| 93 | + properties: | |
| 94 | + interrupts: | |
| 95 | + maxItems: 2 | |
| 96 | + ports: | |
| 97 | + properties: | |
| 98 | + port@0: | |
| 99 | + description: MIPI CSI-2 RX 0 | |
| 100 | + port@1: | |
| 101 | + description: MIPI CSI-2 RX 1 | |
| 102 | + required: | |
| 103 | + - port@0 | |
| 104 | + - port@1 | |
| 105 | + | |
| 106 | +additionalProperties: false | |
| 107 | + | |
| 108 | +examples: | |
| 109 | + - | | |
| 110 | + #include <dt-bindings/clock/imx8mn-clock.h> | |
| 111 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 112 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 113 | + #include <dt-bindings/power/imx8mn-power.h> | |
| 114 | + | |
| 115 | + isi@32e20000 { | |
| 116 | + compatible = "fsl,imx8mn-isi"; | |
| 117 | + reg = <0x32e20000 0x100>; | |
| 118 | + interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; | |
| 119 | + clocks = <&clk IMX8MN_CLK_DISP_AXI_ROOT>, | |
| 120 | + <&clk IMX8MN_CLK_DISP_APB_ROOT>; | |
| 121 | + clock-names = "axi", "apb"; | |
| 122 | + fsl,blk-ctrl = <&disp_blk_ctrl>; | |
| 123 | + power-domains = <&disp_blk_ctrl IMX8MN_DISPBLK_PD_ISI>; | |
| 124 | + | |
| 125 | + ports { | |
| 126 | + #address-cells = <1>; | |
| 127 | + #size-cells = <0>; | |
| 128 | + | |
| 129 | + port@0 { | |
| 130 | + reg = <0>; | |
| 131 | + isi_in: endpoint { | |
| 132 | + remote-endpoint = <&mipi_csi_out>; | |
| 133 | + }; | |
| 134 | + }; | |
| 135 | + }; | |
| 136 | + }; | |
| 137 | + | |
| 138 | + - | | |
| 139 | + #include <dt-bindings/clock/imx8mp-clock.h> | |
| 140 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 141 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 142 | + | |
| 143 | + isi@32e00000 { | |
| 144 | + compatible = "fsl,imx8mp-isi"; | |
| 145 | + reg = <0x32e00000 0x4000>; | |
| 146 | + interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>, | |
| 147 | + <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>; | |
| 148 | + clocks = <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>, | |
| 149 | + <&clk IMX8MP_CLK_MEDIA_APB_ROOT>; | |
| 150 | + clock-names = "axi", "apb"; | |
| 151 | + fsl,blk-ctrl = <&media_blk_ctrl>; | |
| 152 | + power-domains = <&mediamix_pd>; | |
| 153 | + | |
| 154 | + ports { | |
| 155 | + #address-cells = <1>; | |
| 156 | + #size-cells = <0>; | |
| 157 | + | |
| 158 | + port@0 { | |
| 159 | + reg = <0>; | |
| 160 | + isi_in_0: endpoint { | |
| 161 | + remote-endpoint = <&mipi_csi_0_out>; | |
| 162 | + }; | |
| 163 | + }; | |
| 164 | + | |
| 165 | + port@1 { | |
| 166 | + reg = <1>; | |
| 167 | + isi_in_1: endpoint { | |
| 168 | + remote-endpoint = <&mipi_csi_1_out>; | |
| 169 | + }; | |
| 170 | + }; | |
| 171 | + }; | |
| 172 | + }; | |
| 173 | +... | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/nxp,imx8mq-vpu.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/nxp,imx8mq-vpu.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Hantro G1/G2 VPU codecs implemented on i.MX8M SoCs |
| 9 | 9 | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,msm8916-camss.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/qcom,msm8916-camss.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Qualcomm CAMSS ISP |
| 9 | 9 | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,msm8916-venus.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,msm8916-venus.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm MSM8916 Venus video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -14,16 +13,13 @@ description: | · 2 unmodified lines | ||
| 14 | 13 | The Venus IP is a video encode and decode accelerator present |
| 15 | 14 | on Qualcomm platforms |
| 16 | 15 | |
| 16 | +allOf: | |
| 17 | + - $ref: qcom,venus-common.yaml# | |
| 18 | + | |
| 17 | 19 | properties: |
| 18 | 20 | compatible: |
| 19 | 21 | const: qcom,msm8916-venus |
| 20 | 22 | |
| 21 | − reg: | |
| 22 | − maxItems: 1 | |
| 23 | − | |
| 24 | − interrupts: | |
| 25 | − maxItems: 1 | |
| 26 | − | |
| 27 | 23 | power-domains: |
| 28 | 24 | maxItems: 1 |
| 29 | 25 | |
| @@ -39,9 +35,6 @@ properties: · 9 unmodified lines | ||
| 39 | 35 | iommus: |
| 40 | 36 | maxItems: 1 |
| 41 | 37 | |
| 42 | − memory-region: | |
| 43 | − maxItems: 1 | |
| 44 | − | |
| 45 | 38 | video-decoder: |
| 46 | 39 | type: object |
| 47 | 40 | |
| @@ -66,57 +59,36 @@ properties: · 18 unmodified lines | ||
| 66 | 59 | |
| 67 | 60 | additionalProperties: false |
| 68 | 61 | |
| 69 | − video-firmware: | |
| 70 | − type: object | |
| 71 | − additionalProperties: false | |
| 72 | − | |
| 73 | − description: | | |
| 74 | − Firmware subnode is needed when the platform does not | |
| 75 | − have TrustZone. | |
| 76 | − | |
| 77 | − properties: | |
| 78 | − iommus: | |
| 79 | − maxItems: 1 | |
| 80 | − | |
| 81 | − required: | |
| 82 | − - iommus | |
| 83 | − | |
| 84 | 62 | required: |
| 85 | 63 | - compatible |
| 86 | − - reg | |
| 87 | − - interrupts | |
| 88 | − - power-domains | |
| 89 | − - clocks | |
| 90 | − - clock-names | |
| 91 | 64 | - iommus |
| 92 | − - memory-region | |
| 93 | 65 | - video-decoder |
| 94 | 66 | - video-encoder |
| 95 | 67 | |
| 96 | −additionalProperties: false | |
| 68 | +unevaluatedProperties: false | |
| 97 | 69 | |
| 98 | 70 | examples: |
| 99 | 71 | - | |
| 100 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 101 | − #include <dt-bindings/clock/qcom,gcc-msm8916.h> | |
| 102 | − | |
| 103 | − video-codec@1d00000 { | |
| 104 | − compatible = "qcom,msm8916-venus"; | |
| 105 | − reg = <0x01d00000 0xff000>; | |
| 106 | − interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; | |
| 107 | − clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, | |
| 108 | − <&gcc GCC_VENUS0_AHB_CLK>, | |
| 109 | − <&gcc GCC_VENUS0_AXI_CLK>; | |
| 110 | − clock-names = "core", "iface", "bus"; | |
| 111 | − power-domains = <&gcc VENUS_GDSC>; | |
| 112 | − iommus = <&apps_iommu 5>; | |
| 113 | − memory-region = <&venus_mem>; | |
| 114 | − | |
| 115 | − video-decoder { | |
| 116 | − compatible = "venus-decoder"; | |
| 117 | − }; | |
| 118 | − | |
| 119 | − video-encoder { | |
| 120 | − compatible = "venus-encoder"; | |
| 121 | − }; | |
| 72 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 73 | + #include <dt-bindings/clock/qcom,gcc-msm8916.h> | |
| 74 | + | |
| 75 | + video-codec@1d00000 { | |
| 76 | + compatible = "qcom,msm8916-venus"; | |
| 77 | + reg = <0x01d00000 0xff000>; | |
| 78 | + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; | |
| 79 | + clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, | |
| 80 | + <&gcc GCC_VENUS0_AHB_CLK>, | |
| 81 | + <&gcc GCC_VENUS0_AXI_CLK>; | |
| 82 | + clock-names = "core", "iface", "bus"; | |
| 83 | + power-domains = <&gcc VENUS_GDSC>; | |
| 84 | + iommus = <&apps_iommu 5>; | |
| 85 | + memory-region = <&venus_mem>; | |
| 86 | + | |
| 87 | + video-decoder { | |
| 88 | + compatible = "venus-decoder"; | |
| 89 | + }; | |
| 90 | + | |
| 91 | + video-encoder { | |
| 92 | + compatible = "venus-encoder"; | |
| 122 | 93 | }; |
| 94 | + }; | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,msm8996-camss.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/qcom,msm8996-camss.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Qualcomm CAMSS ISP |
| 9 | 9 | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,msm8996-venus.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,msm8996-venus.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm MSM8996 Venus video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -14,16 +13,13 @@ description: | · 2 unmodified lines | ||
| 14 | 13 | The Venus IP is a video encode and decode accelerator present |
| 15 | 14 | on Qualcomm platforms |
| 16 | 15 | |
| 16 | +allOf: | |
| 17 | + - $ref: qcom,venus-common.yaml# | |
| 18 | + | |
| 17 | 19 | properties: |
| 18 | 20 | compatible: |
| 19 | 21 | const: qcom,msm8996-venus |
| 20 | 22 | |
| 21 | − reg: | |
| 22 | − maxItems: 1 | |
| 23 | − | |
| 24 | − interrupts: | |
| 25 | − maxItems: 1 | |
| 26 | − | |
| 27 | 23 | power-domains: |
| 28 | 24 | maxItems: 1 |
| 29 | 25 | |
| @@ -37,12 +33,17 @@ properties: · 7 unmodified lines | ||
| 37 | 33 | - const: bus |
| 38 | 34 | - const: mbus |
| 39 | 35 | |
| 36 | + interconnects: | |
| 37 | + maxItems: 2 | |
| 38 | + | |
| 39 | + interconnect-names: | |
| 40 | + items: | |
| 41 | + - const: video-mem | |
| 42 | + - const: cpu-cfg | |
| 43 | + | |
| 40 | 44 | iommus: |
| 41 | 45 | maxItems: 20 |
| 42 | 46 | |
| 43 | − memory-region: | |
| 44 | − maxItems: 1 | |
| 45 | − | |
| 46 | 47 | video-decoder: |
| 47 | 48 | type: object |
| 48 | 49 | |
| @@ -93,83 +94,62 @@ properties: · 44 unmodified lines | ||
| 93 | 94 | |
| 94 | 95 | additionalProperties: false |
| 95 | 96 | |
| 96 | − video-firmware: | |
| 97 | − type: object | |
| 98 | − additionalProperties: false | |
| 99 | − | |
| 100 | − description: | | |
| 101 | − Firmware subnode is needed when the platform does not | |
| 102 | − have TrustZone. | |
| 103 | − | |
| 104 | − properties: | |
| 105 | − iommus: | |
| 106 | − maxItems: 1 | |
| 107 | − | |
| 108 | − required: | |
| 109 | − - iommus | |
| 110 | − | |
| 111 | 97 | required: |
| 112 | 98 | - compatible |
| 113 | − - reg | |
| 114 | − - interrupts | |
| 115 | − - power-domains | |
| 116 | − - clocks | |
| 117 | − - clock-names | |
| 118 | 99 | - iommus |
| 119 | − - memory-region | |
| 120 | 100 | - video-decoder |
| 121 | 101 | - video-encoder |
| 122 | 102 | |
| 123 | −additionalProperties: false | |
| 103 | +unevaluatedProperties: false | |
| 124 | 104 | |
| 125 | 105 | examples: |
| 126 | 106 | - | |
| 127 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 128 | − #include <dt-bindings/clock/qcom,mmcc-msm8996.h> | |
| 129 | − | |
| 130 | − video-codec@c00000 { | |
| 131 | − compatible = "qcom,msm8996-venus"; | |
| 132 | − reg = <0x00c00000 0xff000>; | |
| 133 | − interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; | |
| 134 | − clocks = <&mmcc VIDEO_CORE_CLK>, | |
| 135 | − <&mmcc VIDEO_AHB_CLK>, | |
| 136 | − <&mmcc VIDEO_AXI_CLK>, | |
| 137 | − <&mmcc VIDEO_MAXI_CLK>; | |
| 138 | − clock-names = "core", "iface", "bus", "mbus"; | |
| 139 | − power-domains = <&mmcc VENUS_GDSC>; | |
| 140 | − iommus = <&venus_smmu 0x00>, | |
| 141 | − <&venus_smmu 0x01>, | |
| 142 | − <&venus_smmu 0x0a>, | |
| 143 | − <&venus_smmu 0x07>, | |
| 144 | − <&venus_smmu 0x0e>, | |
| 145 | − <&venus_smmu 0x0f>, | |
| 146 | − <&venus_smmu 0x08>, | |
| 147 | − <&venus_smmu 0x09>, | |
| 148 | − <&venus_smmu 0x0b>, | |
| 149 | − <&venus_smmu 0x0c>, | |
| 150 | − <&venus_smmu 0x0d>, | |
| 151 | − <&venus_smmu 0x10>, | |
| 152 | − <&venus_smmu 0x11>, | |
| 153 | − <&venus_smmu 0x21>, | |
| 154 | − <&venus_smmu 0x28>, | |
| 155 | − <&venus_smmu 0x29>, | |
| 156 | − <&venus_smmu 0x2b>, | |
| 157 | − <&venus_smmu 0x2c>, | |
| 158 | − <&venus_smmu 0x2d>, | |
| 159 | − <&venus_smmu 0x31>; | |
| 160 | − memory-region = <&venus_mem>; | |
| 161 | − | |
| 162 | − video-decoder { | |
| 163 | − compatible = "venus-decoder"; | |
| 164 | − clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 165 | − clock-names = "core"; | |
| 166 | − power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 167 | − }; | |
| 168 | − | |
| 169 | − video-encoder { | |
| 170 | − compatible = "venus-encoder"; | |
| 171 | − clocks = <&mmcc VIDEO_SUBCORE1_CLK>; | |
| 172 | − clock-names = "core"; | |
| 173 | − power-domains = <&mmcc VENUS_CORE1_GDSC>; | |
| 174 | − }; | |
| 107 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 108 | + #include <dt-bindings/clock/qcom,mmcc-msm8996.h> | |
| 109 | + | |
| 110 | + video-codec@c00000 { | |
| 111 | + compatible = "qcom,msm8996-venus"; | |
| 112 | + reg = <0x00c00000 0xff000>; | |
| 113 | + interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; | |
| 114 | + clocks = <&mmcc VIDEO_CORE_CLK>, | |
| 115 | + <&mmcc VIDEO_AHB_CLK>, | |
| 116 | + <&mmcc VIDEO_AXI_CLK>, | |
| 117 | + <&mmcc VIDEO_MAXI_CLK>; | |
| 118 | + clock-names = "core", "iface", "bus", "mbus"; | |
| 119 | + power-domains = <&mmcc VENUS_GDSC>; | |
| 120 | + iommus = <&venus_smmu 0x00>, | |
| 121 | + <&venus_smmu 0x01>, | |
| 122 | + <&venus_smmu 0x0a>, | |
| 123 | + <&venus_smmu 0x07>, | |
| 124 | + <&venus_smmu 0x0e>, | |
| 125 | + <&venus_smmu 0x0f>, | |
| 126 | + <&venus_smmu 0x08>, | |
| 127 | + <&venus_smmu 0x09>, | |
| 128 | + <&venus_smmu 0x0b>, | |
| 129 | + <&venus_smmu 0x0c>, | |
| 130 | + <&venus_smmu 0x0d>, | |
| 131 | + <&venus_smmu 0x10>, | |
| 132 | + <&venus_smmu 0x11>, | |
| 133 | + <&venus_smmu 0x21>, | |
| 134 | + <&venus_smmu 0x28>, | |
| 135 | + <&venus_smmu 0x29>, | |
| 136 | + <&venus_smmu 0x2b>, | |
| 137 | + <&venus_smmu 0x2c>, | |
| 138 | + <&venus_smmu 0x2d>, | |
| 139 | + <&venus_smmu 0x31>; | |
| 140 | + memory-region = <&venus_mem>; | |
| 141 | + | |
| 142 | + video-decoder { | |
| 143 | + compatible = "venus-decoder"; | |
| 144 | + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 145 | + clock-names = "core"; | |
| 146 | + power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 147 | + }; | |
| 148 | + | |
| 149 | + video-encoder { | |
| 150 | + compatible = "venus-encoder"; | |
| 151 | + clocks = <&mmcc VIDEO_SUBCORE1_CLK>; | |
| 152 | + clock-names = "core"; | |
| 153 | + power-domains = <&mmcc VENUS_CORE1_GDSC>; | |
| 175 | 154 | }; |
| 155 | + }; | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sc7180-venus.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,sc7180-venus.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm SC7180 Venus video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -14,16 +13,13 @@ description: | · 2 unmodified lines | ||
| 14 | 13 | The Venus IP is a video encode and decode accelerator present |
| 15 | 14 | on Qualcomm platforms |
| 16 | 15 | |
| 16 | +allOf: | |
| 17 | + - $ref: qcom,venus-common.yaml# | |
| 18 | + | |
| 17 | 19 | properties: |
| 18 | 20 | compatible: |
| 19 | 21 | const: qcom,sc7180-venus |
| 20 | 22 | |
| 21 | − reg: | |
| 22 | − maxItems: 1 | |
| 23 | − | |
| 24 | − interrupts: | |
| 25 | − maxItems: 1 | |
| 26 | − | |
| 27 | 23 | power-domains: |
| 28 | 24 | minItems: 2 |
| 29 | 25 | maxItems: 3 |
| @@ -60,6 +56,10 @@ properties: · 30 unmodified lines | ||
| 60 | 56 | - const: video-mem |
| 61 | 57 | - const: cpu-cfg |
| 62 | 58 | |
| 59 | + operating-points-v2: true | |
| 60 | + opp-table: | |
| 61 | + type: object | |
| 62 | + | |
| 63 | 63 | video-decoder: |
| 64 | 64 | type: object |
| 65 | 65 | |
| @@ -84,63 +84,42 @@ properties: · 18 unmodified lines | ||
| 84 | 84 | |
| 85 | 85 | additionalProperties: false |
| 86 | 86 | |
| 87 | − video-firmware: | |
| 88 | − type: object | |
| 89 | − additionalProperties: false | |
| 90 | − | |
| 91 | − description: | | |
| 92 | − Firmware subnode is needed when the platform does not | |
| 93 | − have TrustZone. | |
| 94 | − | |
| 95 | − properties: | |
| 96 | − iommus: | |
| 97 | − maxItems: 1 | |
| 98 | − | |
| 99 | − required: | |
| 100 | − - iommus | |
| 101 | − | |
| 102 | 87 | required: |
| 103 | 88 | - compatible |
| 104 | − - reg | |
| 105 | − - interrupts | |
| 106 | − - power-domains | |
| 107 | 89 | - power-domain-names |
| 108 | − - clocks | |
| 109 | − - clock-names | |
| 110 | 90 | - iommus |
| 111 | − - memory-region | |
| 112 | 91 | - video-decoder |
| 113 | 92 | - video-encoder |
| 114 | 93 | |
| 115 | −additionalProperties: false | |
| 94 | +unevaluatedProperties: false | |
| 116 | 95 | |
| 117 | 96 | examples: |
| 118 | 97 | - | |
| 119 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 120 | − #include <dt-bindings/clock/qcom,videocc-sc7180.h> | |
| 121 | − | |
| 122 | − venus: video-codec@aa00000 { | |
| 123 | − compatible = "qcom,sc7180-venus"; | |
| 124 | − reg = <0x0aa00000 0xff000>; | |
| 125 | − interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 126 | − power-domains = <&videocc VENUS_GDSC>, | |
| 127 | − <&videocc VCODEC0_GDSC>; | |
| 128 | − power-domain-names = "venus", "vcodec0"; | |
| 129 | − clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 130 | − <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 131 | − <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, | |
| 132 | − <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 133 | − <&videocc VIDEO_CC_VCODEC0_AXI_CLK>; | |
| 134 | − clock-names = "core", "iface", "bus", | |
| 135 | − "vcodec0_core", "vcodec0_bus"; | |
| 136 | − iommus = <&apps_smmu 0x0c00 0x60>; | |
| 137 | − memory-region = <&venus_mem>; | |
| 138 | − | |
| 139 | − video-decoder { | |
| 140 | − compatible = "venus-decoder"; | |
| 141 | − }; | |
| 142 | − | |
| 143 | − video-encoder { | |
| 144 | − compatible = "venus-encoder"; | |
| 145 | − }; | |
| 98 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 99 | + #include <dt-bindings/clock/qcom,videocc-sc7180.h> | |
| 100 | + | |
| 101 | + venus: video-codec@aa00000 { | |
| 102 | + compatible = "qcom,sc7180-venus"; | |
| 103 | + reg = <0x0aa00000 0xff000>; | |
| 104 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 105 | + power-domains = <&videocc VENUS_GDSC>, | |
| 106 | + <&videocc VCODEC0_GDSC>; | |
| 107 | + power-domain-names = "venus", "vcodec0"; | |
| 108 | + clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 109 | + <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 110 | + <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, | |
| 111 | + <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 112 | + <&videocc VIDEO_CC_VCODEC0_AXI_CLK>; | |
| 113 | + clock-names = "core", "iface", "bus", | |
| 114 | + "vcodec0_core", "vcodec0_bus"; | |
| 115 | + iommus = <&apps_smmu 0x0c00 0x60>; | |
| 116 | + memory-region = <&venus_mem>; | |
| 117 | + | |
| 118 | + video-decoder { | |
| 119 | + compatible = "venus-decoder"; | |
| 120 | + }; | |
| 121 | + | |
| 122 | + video-encoder { | |
| 123 | + compatible = "venus-encoder"; | |
| 146 | 124 | }; |
| 125 | + }; | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sc7280-venus.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,sc7280-venus.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm SC7280 Venus video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -14,16 +13,13 @@ description: | · 2 unmodified lines | ||
| 14 | 13 | The Venus Iris2 IP is a video encode and decode accelerator present |
| 15 | 14 | on Qualcomm platforms |
| 16 | 15 | |
| 16 | +allOf: | |
| 17 | + - $ref: qcom,venus-common.yaml# | |
| 18 | + | |
| 17 | 19 | properties: |
| 18 | 20 | compatible: |
| 19 | 21 | const: qcom,sc7280-venus |
| 20 | 22 | |
| 21 | − reg: | |
| 22 | − maxItems: 1 | |
| 23 | − | |
| 24 | − interrupts: | |
| 25 | − maxItems: 1 | |
| 26 | − | |
| 27 | 23 | power-domains: |
| 28 | 24 | minItems: 2 |
| 29 | 25 | maxItems: 3 |
| @@ -49,9 +45,6 @@ properties: · 19 unmodified lines | ||
| 49 | 45 | iommus: |
| 50 | 46 | maxItems: 2 |
| 51 | 47 | |
| 52 | − memory-region: | |
| 53 | − maxItems: 1 | |
| 54 | − | |
| 55 | 48 | interconnects: |
| 56 | 49 | maxItems: 2 |
| 57 | 50 | |
| @@ -60,6 +53,10 @@ properties: · 2 unmodified lines | ||
| 60 | 53 | - const: cpu-cfg |
| 61 | 54 | - const: video-mem |
| 62 | 55 | |
| 56 | + operating-points-v2: true | |
| 57 | + opp-table: | |
| 58 | + type: object | |
| 59 | + | |
| 63 | 60 | video-decoder: |
| 64 | 61 | type: object |
| 65 | 62 | |
| @@ -84,79 +81,58 @@ properties: · 18 unmodified lines | ||
| 84 | 81 | |
| 85 | 82 | additionalProperties: false |
| 86 | 83 | |
| 87 | − video-firmware: | |
| 88 | − type: object | |
| 89 | − additionalProperties: false | |
| 90 | − | |
| 91 | − description: | | |
| 92 | − Firmware subnode is needed when the platform does not | |
| 93 | − have TrustZone. | |
| 94 | − | |
| 95 | − properties: | |
| 96 | − iommus: | |
| 97 | − maxItems: 1 | |
| 98 | − | |
| 99 | − required: | |
| 100 | − - iommus | |
| 101 | − | |
| 102 | 84 | required: |
| 103 | 85 | - compatible |
| 104 | − - reg | |
| 105 | − - interrupts | |
| 106 | − - power-domains | |
| 107 | 86 | - power-domain-names |
| 108 | − - clocks | |
| 109 | − - clock-names | |
| 110 | 87 | - iommus |
| 111 | − - memory-region | |
| 112 | 88 | - video-decoder |
| 113 | 89 | - video-encoder |
| 114 | 90 | |
| 115 | −additionalProperties: false | |
| 91 | +unevaluatedProperties: false | |
| 116 | 92 | |
| 117 | 93 | examples: |
| 118 | 94 | - | |
| 119 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 120 | − #include <dt-bindings/clock/qcom,videocc-sc7280.h> | |
| 121 | − #include <dt-bindings/interconnect/qcom,sc7280.h> | |
| 122 | − #include <dt-bindings/power/qcom-rpmpd.h> | |
| 123 | − | |
| 124 | − venus: video-codec@aa00000 { | |
| 125 | − compatible = "qcom,sc7280-venus"; | |
| 126 | − reg = <0x0aa00000 0xd0600>; | |
| 127 | − interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 128 | − | |
| 129 | − clocks = <&videocc VIDEO_CC_MVSC_CORE_CLK>, | |
| 130 | − <&videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, | |
| 131 | − <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 132 | − <&videocc VIDEO_CC_MVS0_CORE_CLK>, | |
| 133 | − <&videocc VIDEO_CC_MVS0_AXI_CLK>; | |
| 134 | − clock-names = "core", "bus", "iface", | |
| 135 | − "vcodec_core", "vcodec_bus"; | |
| 136 | − | |
| 137 | − power-domains = <&videocc MVSC_GDSC>, | |
| 138 | − <&videocc MVS0_GDSC>, | |
| 139 | − <&rpmhpd SC7280_CX>; | |
| 140 | − power-domain-names = "venus", "vcodec0", "cx"; | |
| 141 | − | |
| 142 | − interconnects = <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_VENUS_CFG 0>, | |
| 143 | − <&mmss_noc MASTER_VIDEO_P0 0 &mc_virt SLAVE_EBI1 0>; | |
| 144 | − interconnect-names = "cpu-cfg", "video-mem"; | |
| 145 | − | |
| 146 | − iommus = <&apps_smmu 0x2180 0x20>, | |
| 147 | − <&apps_smmu 0x2184 0x20>; | |
| 148 | − | |
| 149 | − memory-region = <&video_mem>; | |
| 150 | − | |
| 151 | − video-decoder { | |
| 152 | − compatible = "venus-decoder"; | |
| 153 | − }; | |
| 154 | − | |
| 155 | − video-encoder { | |
| 156 | − compatible = "venus-encoder"; | |
| 157 | − }; | |
| 158 | − | |
| 159 | − video-firmware { | |
| 160 | − iommus = <&apps_smmu 0x21a2 0x0>; | |
| 161 | − }; | |
| 95 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 96 | + #include <dt-bindings/clock/qcom,videocc-sc7280.h> | |
| 97 | + #include <dt-bindings/interconnect/qcom,sc7280.h> | |
| 98 | + #include <dt-bindings/power/qcom-rpmpd.h> | |
| 99 | + | |
| 100 | + venus: video-codec@aa00000 { | |
| 101 | + compatible = "qcom,sc7280-venus"; | |
| 102 | + reg = <0x0aa00000 0xd0600>; | |
| 103 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 104 | + | |
| 105 | + clocks = <&videocc VIDEO_CC_MVSC_CORE_CLK>, | |
| 106 | + <&videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, | |
| 107 | + <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 108 | + <&videocc VIDEO_CC_MVS0_CORE_CLK>, | |
| 109 | + <&videocc VIDEO_CC_MVS0_AXI_CLK>; | |
| 110 | + clock-names = "core", "bus", "iface", | |
| 111 | + "vcodec_core", "vcodec_bus"; | |
| 112 | + | |
| 113 | + power-domains = <&videocc MVSC_GDSC>, | |
| 114 | + <&videocc MVS0_GDSC>, | |
| 115 | + <&rpmhpd SC7280_CX>; | |
| 116 | + power-domain-names = "venus", "vcodec0", "cx"; | |
| 117 | + | |
| 118 | + interconnects = <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_VENUS_CFG 0>, | |
| 119 | + <&mmss_noc MASTER_VIDEO_P0 0 &mc_virt SLAVE_EBI1 0>; | |
| 120 | + interconnect-names = "cpu-cfg", "video-mem"; | |
| 121 | + | |
| 122 | + iommus = <&apps_smmu 0x2180 0x20>, | |
| 123 | + <&apps_smmu 0x2184 0x20>; | |
| 124 | + | |
| 125 | + memory-region = <&video_mem>; | |
| 126 | + | |
| 127 | + video-decoder { | |
| 128 | + compatible = "venus-decoder"; | |
| 129 | + }; | |
| 130 | + | |
| 131 | + video-encoder { | |
| 132 | + compatible = "venus-encoder"; | |
| 133 | + }; | |
| 134 | + | |
| 135 | + video-firmware { | |
| 136 | + iommus = <&apps_smmu 0x21a2 0x0>; | |
| 162 | 137 | }; |
| 138 | + }; | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sdm660-camss.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/qcom,sdm660-camss.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Qualcomm CAMSS ISP |
| 9 | 9 | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sdm660-venus.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,sdm660-venus.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm SDM660 Venus video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -15,13 +14,13 @@ description: | · 3 unmodified lines | ||
| 15 | 14 | The Venus IP is a video encode and decode accelerator present |
| 16 | 15 | on Qualcomm platforms |
| 17 | 16 | |
| 17 | +allOf: | |
| 18 | + - $ref: qcom,venus-common.yaml# | |
| 19 | + | |
| 18 | 20 | properties: |
| 19 | 21 | compatible: |
| 20 | 22 | const: qcom,sdm660-venus |
| 21 | 23 | |
| 22 | − reg: | |
| 23 | − maxItems: 1 | |
| 24 | − | |
| 25 | 24 | clocks: |
| 26 | 25 | maxItems: 4 |
| 27 | 26 | |
| @@ -40,15 +39,9 @@ properties: · 12 unmodified lines | ||
| 40 | 39 | - const: cpu-cfg |
| 41 | 40 | - const: video-mem |
| 42 | 41 | |
| 43 | − interrupts: | |
| 44 | − maxItems: 1 | |
| 45 | − | |
| 46 | 42 | iommus: |
| 47 | 43 | maxItems: 20 |
| 48 | 44 | |
| 49 | − memory-region: | |
| 50 | − maxItems: 1 | |
| 51 | − | |
| 52 | 45 | power-domains: |
| 53 | 46 | maxItems: 1 |
| 54 | 47 | |
| @@ -102,86 +95,65 @@ properties: · 47 unmodified lines | ||
| 102 | 95 | |
| 103 | 96 | additionalProperties: false |
| 104 | 97 | |
| 105 | − video-firmware: | |
| 106 | − type: object | |
| 107 | − additionalProperties: false | |
| 108 | − | |
| 109 | − description: | | |
| 110 | − Firmware subnode is needed when the platform does not | |
| 111 | − have TrustZone. | |
| 112 | − | |
| 113 | − properties: | |
| 114 | − iommus: | |
| 115 | − maxItems: 1 | |
| 116 | − | |
| 117 | − required: | |
| 118 | − - iommus | |
| 119 | − | |
| 120 | 98 | required: |
| 121 | 99 | - compatible |
| 122 | − - reg | |
| 123 | − - clocks | |
| 124 | − - clock-names | |
| 125 | − - interrupts | |
| 126 | 100 | - iommus |
| 127 | − - memory-region | |
| 128 | − - power-domains | |
| 129 | 101 | - video-decoder |
| 130 | 102 | - video-encoder |
| 131 | 103 | |
| 132 | −additionalProperties: false | |
| 104 | +unevaluatedProperties: false | |
| 133 | 105 | |
| 134 | 106 | examples: |
| 135 | 107 | - | |
| 136 | − #include <dt-bindings/clock/qcom,mmcc-sdm660.h> | |
| 137 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 138 | − | |
| 139 | − video-codec@cc00000 { | |
| 140 | − compatible = "qcom,sdm660-venus"; | |
| 141 | − reg = <0x0cc00000 0xff000>; | |
| 142 | − clocks = <&mmcc VIDEO_CORE_CLK>, | |
| 143 | − <&mmcc VIDEO_AHB_CLK>, | |
| 144 | − <&mmcc VIDEO_AXI_CLK>, | |
| 145 | − <&mmcc THROTTLE_VIDEO_AXI_CLK>; | |
| 146 | − clock-names = "core", "iface", "bus", "bus_throttle"; | |
| 147 | − interconnects = <&gnoc 0 &mnoc 13>, | |
| 148 | − <&mnoc 4 &bimc 5>; | |
| 149 | − interconnect-names = "cpu-cfg", "video-mem"; | |
| 150 | − interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; | |
| 151 | − iommus = <&mmss_smmu 0x400>, | |
| 152 | − <&mmss_smmu 0x401>, | |
| 153 | − <&mmss_smmu 0x40a>, | |
| 154 | − <&mmss_smmu 0x407>, | |
| 155 | − <&mmss_smmu 0x40e>, | |
| 156 | − <&mmss_smmu 0x40f>, | |
| 157 | − <&mmss_smmu 0x408>, | |
| 158 | − <&mmss_smmu 0x409>, | |
| 159 | − <&mmss_smmu 0x40b>, | |
| 160 | − <&mmss_smmu 0x40c>, | |
| 161 | − <&mmss_smmu 0x40d>, | |
| 162 | − <&mmss_smmu 0x410>, | |
| 163 | − <&mmss_smmu 0x421>, | |
| 164 | − <&mmss_smmu 0x428>, | |
| 165 | − <&mmss_smmu 0x429>, | |
| 166 | − <&mmss_smmu 0x42b>, | |
| 167 | − <&mmss_smmu 0x42c>, | |
| 168 | − <&mmss_smmu 0x42d>, | |
| 169 | − <&mmss_smmu 0x411>, | |
| 170 | − <&mmss_smmu 0x431>; | |
| 171 | − memory-region = <&venus_region>; | |
| 172 | − power-domains = <&mmcc VENUS_GDSC>; | |
| 173 | − | |
| 174 | − video-decoder { | |
| 175 | − compatible = "venus-decoder"; | |
| 176 | − clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 177 | − clock-names = "vcodec0_core"; | |
| 178 | − power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 179 | − }; | |
| 180 | − | |
| 181 | − video-encoder { | |
| 182 | − compatible = "venus-encoder"; | |
| 183 | − clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 184 | − clock-names = "vcodec0_core"; | |
| 185 | − power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 186 | − }; | |
| 108 | + #include <dt-bindings/clock/qcom,mmcc-sdm660.h> | |
| 109 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 110 | + | |
| 111 | + video-codec@cc00000 { | |
| 112 | + compatible = "qcom,sdm660-venus"; | |
| 113 | + reg = <0x0cc00000 0xff000>; | |
| 114 | + clocks = <&mmcc VIDEO_CORE_CLK>, | |
| 115 | + <&mmcc VIDEO_AHB_CLK>, | |
| 116 | + <&mmcc VIDEO_AXI_CLK>, | |
| 117 | + <&mmcc THROTTLE_VIDEO_AXI_CLK>; | |
| 118 | + clock-names = "core", "iface", "bus", "bus_throttle"; | |
| 119 | + interconnects = <&gnoc 0 &mnoc 13>, | |
| 120 | + <&mnoc 4 &bimc 5>; | |
| 121 | + interconnect-names = "cpu-cfg", "video-mem"; | |
| 122 | + interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; | |
| 123 | + iommus = <&mmss_smmu 0x400>, | |
| 124 | + <&mmss_smmu 0x401>, | |
| 125 | + <&mmss_smmu 0x40a>, | |
| 126 | + <&mmss_smmu 0x407>, | |
| 127 | + <&mmss_smmu 0x40e>, | |
| 128 | + <&mmss_smmu 0x40f>, | |
| 129 | + <&mmss_smmu 0x408>, | |
| 130 | + <&mmss_smmu 0x409>, | |
| 131 | + <&mmss_smmu 0x40b>, | |
| 132 | + <&mmss_smmu 0x40c>, | |
| 133 | + <&mmss_smmu 0x40d>, | |
| 134 | + <&mmss_smmu 0x410>, | |
| 135 | + <&mmss_smmu 0x421>, | |
| 136 | + <&mmss_smmu 0x428>, | |
| 137 | + <&mmss_smmu 0x429>, | |
| 138 | + <&mmss_smmu 0x42b>, | |
| 139 | + <&mmss_smmu 0x42c>, | |
| 140 | + <&mmss_smmu 0x42d>, | |
| 141 | + <&mmss_smmu 0x411>, | |
| 142 | + <&mmss_smmu 0x431>; | |
| 143 | + memory-region = <&venus_region>; | |
| 144 | + power-domains = <&mmcc VENUS_GDSC>; | |
| 145 | + | |
| 146 | + video-decoder { | |
| 147 | + compatible = "venus-decoder"; | |
| 148 | + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 149 | + clock-names = "vcodec0_core"; | |
| 150 | + power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 151 | + }; | |
| 152 | + | |
| 153 | + video-encoder { | |
| 154 | + compatible = "venus-encoder"; | |
| 155 | + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 156 | + clock-names = "vcodec0_core"; | |
| 157 | + power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 187 | 158 | }; |
| 159 | + }; | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sdm845-camss.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/qcom,sdm845-camss.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Qualcomm CAMSS ISP |
| 9 | 9 | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sdm845-venus-v2.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,sdm845-venus-v2.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm SDM845 Venus v2 video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -14,16 +13,13 @@ description: | · 2 unmodified lines | ||
| 14 | 13 | The Venus IP is a video encode and decode accelerator present |
| 15 | 14 | on Qualcomm platforms |
| 16 | 15 | |
| 16 | +allOf: | |
| 17 | + - $ref: qcom,venus-common.yaml# | |
| 18 | + | |
| 17 | 19 | properties: |
| 18 | 20 | compatible: |
| 19 | 21 | const: qcom,sdm845-venus-v2 |
| 20 | 22 | |
| 21 | − reg: | |
| 22 | − maxItems: 1 | |
| 23 | − | |
| 24 | − interrupts: | |
| 25 | − maxItems: 1 | |
| 26 | − | |
| 27 | 23 | power-domains: |
| 28 | 24 | minItems: 3 |
| 29 | 25 | maxItems: 4 |
| @@ -52,8 +48,9 @@ properties: · 22 unmodified lines | ||
| 52 | 48 | iommus: |
| 53 | 49 | maxItems: 2 |
| 54 | 50 | |
| 55 | − memory-region: | |
| 56 | − maxItems: 1 | |
| 51 | + operating-points-v2: true | |
| 52 | + opp-table: | |
| 53 | + type: object | |
| 57 | 54 | |
| 58 | 55 | video-core0: |
| 59 | 56 | type: object |
| @@ -79,68 +76,47 @@ properties: · 19 unmodified lines | ||
| 79 | 76 | |
| 80 | 77 | additionalProperties: false |
| 81 | 78 | |
| 82 | − video-firmware: | |
| 83 | − type: object | |
| 84 | − additionalProperties: false | |
| 85 | − | |
| 86 | − description: | | |
| 87 | − Firmware subnode is needed when the platform does not | |
| 88 | − have TrustZone. | |
| 89 | − | |
| 90 | − properties: | |
| 91 | − iommus: | |
| 92 | − maxItems: 1 | |
| 93 | − | |
| 94 | − required: | |
| 95 | − - iommus | |
| 96 | − | |
| 97 | 79 | required: |
| 98 | 80 | - compatible |
| 99 | − - reg | |
| 100 | − - interrupts | |
| 101 | − - power-domains | |
| 102 | 81 | - power-domain-names |
| 103 | − - clocks | |
| 104 | − - clock-names | |
| 105 | 82 | - iommus |
| 106 | − - memory-region | |
| 107 | 83 | - video-core0 |
| 108 | 84 | - video-core1 |
| 109 | 85 | |
| 110 | −additionalProperties: false | |
| 86 | +unevaluatedProperties: false | |
| 111 | 87 | |
| 112 | 88 | examples: |
| 113 | 89 | - | |
| 114 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 115 | − #include <dt-bindings/clock/qcom,videocc-sdm845.h> | |
| 116 | − | |
| 117 | − video-codec@aa00000 { | |
| 118 | − compatible = "qcom,sdm845-venus-v2"; | |
| 119 | − reg = <0x0aa00000 0xff000>; | |
| 120 | − interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 121 | − clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 122 | − <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 123 | − <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, | |
| 124 | − <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 125 | − <&videocc VIDEO_CC_VCODEC0_AXI_CLK>, | |
| 126 | − <&videocc VIDEO_CC_VCODEC1_CORE_CLK>, | |
| 127 | − <&videocc VIDEO_CC_VCODEC1_AXI_CLK>; | |
| 128 | − clock-names = "core", "iface", "bus", | |
| 129 | − "vcodec0_core", "vcodec0_bus", | |
| 130 | − "vcodec1_core", "vcodec1_bus"; | |
| 131 | − power-domains = <&videocc VENUS_GDSC>, | |
| 132 | − <&videocc VCODEC0_GDSC>, | |
| 133 | − <&videocc VCODEC1_GDSC>; | |
| 134 | − power-domain-names = "venus", "vcodec0", "vcodec1"; | |
| 135 | − iommus = <&apps_smmu 0x10a0 0x8>, | |
| 136 | − <&apps_smmu 0x10b0 0x0>; | |
| 137 | − memory-region = <&venus_mem>; | |
| 138 | − | |
| 139 | − video-core0 { | |
| 140 | − compatible = "venus-decoder"; | |
| 141 | − }; | |
| 142 | − | |
| 143 | − video-core1 { | |
| 144 | − compatible = "venus-encoder"; | |
| 145 | − }; | |
| 90 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 91 | + #include <dt-bindings/clock/qcom,videocc-sdm845.h> | |
| 92 | + | |
| 93 | + video-codec@aa00000 { | |
| 94 | + compatible = "qcom,sdm845-venus-v2"; | |
| 95 | + reg = <0x0aa00000 0xff000>; | |
| 96 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 97 | + clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 98 | + <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 99 | + <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, | |
| 100 | + <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 101 | + <&videocc VIDEO_CC_VCODEC0_AXI_CLK>, | |
| 102 | + <&videocc VIDEO_CC_VCODEC1_CORE_CLK>, | |
| 103 | + <&videocc VIDEO_CC_VCODEC1_AXI_CLK>; | |
| 104 | + clock-names = "core", "iface", "bus", | |
| 105 | + "vcodec0_core", "vcodec0_bus", | |
| 106 | + "vcodec1_core", "vcodec1_bus"; | |
| 107 | + power-domains = <&videocc VENUS_GDSC>, | |
| 108 | + <&videocc VCODEC0_GDSC>, | |
| 109 | + <&videocc VCODEC1_GDSC>; | |
| 110 | + power-domain-names = "venus", "vcodec0", "vcodec1"; | |
| 111 | + iommus = <&apps_smmu 0x10a0 0x8>, | |
| 112 | + <&apps_smmu 0x10b0 0x0>; | |
| 113 | + memory-region = <&venus_mem>; | |
| 114 | + | |
| 115 | + video-core0 { | |
| 116 | + compatible = "venus-decoder"; | |
| 117 | + }; | |
| 118 | + | |
| 119 | + video-core1 { | |
| 120 | + compatible = "venus-encoder"; | |
| 146 | 121 | }; |
| 122 | + }; | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sdm845-venus.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,sdm845-venus.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm SDM845 Venus video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -14,16 +13,13 @@ description: | · 2 unmodified lines | ||
| 14 | 13 | The Venus IP is a video encode and decode accelerator present |
| 15 | 14 | on Qualcomm platforms |
| 16 | 15 | |
| 16 | +allOf: | |
| 17 | + - $ref: qcom,venus-common.yaml# | |
| 18 | + | |
| 17 | 19 | properties: |
| 18 | 20 | compatible: |
| 19 | 21 | const: qcom,sdm845-venus |
| 20 | 22 | |
| 21 | − reg: | |
| 22 | − maxItems: 1 | |
| 23 | − | |
| 24 | − interrupts: | |
| 25 | − maxItems: 1 | |
| 26 | − | |
| 27 | 23 | power-domains: |
| 28 | 24 | maxItems: 1 |
| 29 | 25 | |
| @@ -39,9 +35,6 @@ properties: · 9 unmodified lines | ||
| 39 | 35 | iommus: |
| 40 | 36 | maxItems: 2 |
| 41 | 37 | |
| 42 | − memory-region: | |
| 43 | − maxItems: 1 | |
| 44 | − | |
| 45 | 38 | video-core0: |
| 46 | 39 | type: object |
| 47 | 40 | |
| @@ -94,66 +87,45 @@ properties: · 46 unmodified lines | ||
| 94 | 87 | |
| 95 | 88 | additionalProperties: false |
| 96 | 89 | |
| 97 | − video-firmware: | |
| 98 | − type: object | |
| 99 | − additionalProperties: false | |
| 100 | − | |
| 101 | − description: | | |
| 102 | − Firmware subnode is needed when the platform does not | |
| 103 | − have TrustZone. | |
| 104 | − | |
| 105 | − properties: | |
| 106 | − iommus: | |
| 107 | − maxItems: 1 | |
| 108 | − | |
| 109 | − required: | |
| 110 | − - iommus | |
| 111 | − | |
| 112 | 90 | required: |
| 113 | 91 | - compatible |
| 114 | − - reg | |
| 115 | − - interrupts | |
| 116 | − - power-domains | |
| 117 | − - clocks | |
| 118 | − - clock-names | |
| 119 | 92 | - iommus |
| 120 | − - memory-region | |
| 121 | 93 | - video-core0 |
| 122 | 94 | - video-core1 |
| 123 | 95 | |
| 124 | −additionalProperties: false | |
| 96 | +unevaluatedProperties: false | |
| 125 | 97 | |
| 126 | 98 | examples: |
| 127 | 99 | - | |
| 128 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 129 | − #include <dt-bindings/clock/qcom,videocc-sdm845.h> | |
| 130 | − | |
| 131 | − video-codec@aa00000 { | |
| 132 | − compatible = "qcom,sdm845-venus"; | |
| 133 | − reg = <0x0aa00000 0xff000>; | |
| 134 | − interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 135 | − clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 136 | − <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 137 | − <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>; | |
| 138 | − clock-names = "core", "iface", "bus"; | |
| 139 | − power-domains = <&videocc VENUS_GDSC>; | |
| 140 | − iommus = <&apps_smmu 0x10a0 0x8>, | |
| 141 | − <&apps_smmu 0x10b0 0x0>; | |
| 142 | − memory-region = <&venus_mem>; | |
| 143 | − | |
| 144 | − video-core0 { | |
| 145 | − compatible = "venus-decoder"; | |
| 146 | − clocks = <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 147 | − <&videocc VIDEO_CC_VCODEC0_AXI_CLK>; | |
| 148 | − clock-names = "core", "bus"; | |
| 149 | − power-domains = <&videocc VCODEC0_GDSC>; | |
| 150 | − }; | |
| 151 | − | |
| 152 | − video-core1 { | |
| 153 | − compatible = "venus-encoder"; | |
| 154 | − clocks = <&videocc VIDEO_CC_VCODEC1_CORE_CLK>, | |
| 155 | − <&videocc VIDEO_CC_VCODEC1_AXI_CLK>; | |
| 156 | − clock-names = "core", "bus"; | |
| 157 | − power-domains = <&videocc VCODEC1_GDSC>; | |
| 158 | − }; | |
| 100 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 101 | + #include <dt-bindings/clock/qcom,videocc-sdm845.h> | |
| 102 | + | |
| 103 | + video-codec@aa00000 { | |
| 104 | + compatible = "qcom,sdm845-venus"; | |
| 105 | + reg = <0x0aa00000 0xff000>; | |
| 106 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 107 | + clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 108 | + <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 109 | + <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>; | |
| 110 | + clock-names = "core", "iface", "bus"; | |
| 111 | + power-domains = <&videocc VENUS_GDSC>; | |
| 112 | + iommus = <&apps_smmu 0x10a0 0x8>, | |
| 113 | + <&apps_smmu 0x10b0 0x0>; | |
| 114 | + memory-region = <&venus_mem>; | |
| 115 | + | |
| 116 | + video-core0 { | |
| 117 | + compatible = "venus-decoder"; | |
| 118 | + clocks = <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 119 | + <&videocc VIDEO_CC_VCODEC0_AXI_CLK>; | |
| 120 | + clock-names = "core", "bus"; | |
| 121 | + power-domains = <&videocc VCODEC0_GDSC>; | |
| 122 | + }; | |
| 123 | + | |
| 124 | + video-core1 { | |
| 125 | + compatible = "venus-encoder"; | |
| 126 | + clocks = <&videocc VIDEO_CC_VCODEC1_CORE_CLK>, | |
| 127 | + <&videocc VIDEO_CC_VCODEC1_AXI_CLK>; | |
| 128 | + clock-names = "core", "bus"; | |
| 129 | + power-domains = <&videocc VCODEC1_GDSC>; | |
| 159 | 130 | }; |
| 131 | + }; | |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sm8250-camss.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/qcom,sm8250-camss.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Qualcomm CAMSS ISP |
| 9 | 9 | |
| @@ -1,11 +1,10 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) |
| 2 | − | |
| 3 | 2 | %YAML 1.2 |
| 4 | 3 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/qcom,sm8250-venus.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,sm8250-venus.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 6 | |
| 8 | −title: Qualcomm Venus video encode and decode accelerators | |
| 7 | +title: Qualcomm SM8250 Venus video encode and decode accelerators | |
| 9 | 8 | |
| 10 | 9 | maintainers: |
| 11 | 10 | - Stanimir Varbanov <stanimir.varbanov@linaro.org> |
| @@ -14,16 +13,13 @@ description: | · 2 unmodified lines | ||
| 14 | 13 | The Venus IP is a video encode and decode accelerator present |
| 15 | 14 | on Qualcomm platforms |
| 16 | 15 | |
| 16 | +allOf: | |
| 17 | + - $ref: qcom,venus-common.yaml# | |
| 18 | + | |
| 17 | 19 | properties: |
| 18 | 20 | compatible: |
| 19 | 21 | const: qcom,sm8250-venus |
| 20 | 22 | |
| 21 | − reg: | |
| 22 | − maxItems: 1 | |
| 23 | − | |
| 24 | − interrupts: | |
| 25 | − maxItems: 1 | |
| 26 | − | |
| 27 | 23 | power-domains: |
| 28 | 24 | minItems: 2 |
| 29 | 25 | maxItems: 3 |
| @@ -47,9 +43,6 @@ properties: · 17 unmodified lines | ||
| 47 | 43 | iommus: |
| 48 | 44 | maxItems: 1 |
| 49 | 45 | |
| 50 | − memory-region: | |
| 51 | − maxItems: 1 | |
| 52 | − | |
| 53 | 46 | interconnects: |
| 54 | 47 | maxItems: 2 |
| 55 | 48 | |
| @@ -58,6 +51,10 @@ properties: · 2 unmodified lines | ||
| 58 | 51 | - const: cpu-cfg |
| 59 | 52 | - const: video-mem |
| 60 | 53 | |
| 54 | + operating-points-v2: true | |
| 55 | + opp-table: | |
| 56 | + type: object | |
| 57 | + | |
| 61 | 58 | resets: |
| 62 | 59 | maxItems: 2 |
| 63 | 60 | |
| @@ -90,78 +87,57 @@ properties: · 26 unmodified lines | ||
| 90 | 87 | |
| 91 | 88 | additionalProperties: false |
| 92 | 89 | |
| 93 | − video-firmware: | |
| 94 | − type: object | |
| 95 | − additionalProperties: false | |
| 96 | − | |
| 97 | − description: | | |
| 98 | − Firmware subnode is needed when the platform does not | |
| 99 | − have TrustZone. | |
| 100 | − | |
| 101 | − properties: | |
| 102 | − iommus: | |
| 103 | − maxItems: 1 | |
| 104 | − | |
| 105 | − required: | |
| 106 | − - iommus | |
| 107 | − | |
| 108 | 90 | required: |
| 109 | 91 | - compatible |
| 110 | − - reg | |
| 111 | − - interrupts | |
| 112 | − - power-domains | |
| 113 | 92 | - power-domain-names |
| 114 | − - clocks | |
| 115 | − - clock-names | |
| 116 | 93 | - interconnects |
| 117 | 94 | - interconnect-names |
| 118 | 95 | - iommus |
| 119 | − - memory-region | |
| 120 | 96 | - resets |
| 121 | 97 | - reset-names |
| 122 | 98 | - video-decoder |
| 123 | 99 | - video-encoder |
| 124 | 100 | |
| 125 | −additionalProperties: false | |
| 101 | +unevaluatedProperties: false | |
| 126 | 102 | |
| 127 | 103 | examples: |
| 128 | 104 | - | |
| 129 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 130 | − #include <dt-bindings/clock/qcom,videocc-sm8250.h> | |
| 131 | − #include <dt-bindings/interconnect/qcom,sm8250.h> | |
| 132 | − #include <dt-bindings/clock/qcom,gcc-sm8250.h> | |
| 133 | − #include <dt-bindings/power/qcom-rpmpd.h> | |
| 134 | − | |
| 135 | − venus: video-codec@aa00000 { | |
| 136 | − compatible = "qcom,sm8250-venus"; | |
| 137 | − reg = <0x0aa00000 0xff000>; | |
| 138 | − interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 139 | − power-domains = <&videocc MVS0C_GDSC>, | |
| 140 | − <&videocc MVS0_GDSC>, | |
| 141 | − <&rpmhpd SM8250_MX>; | |
| 142 | − power-domain-names = "venus", "vcodec0", "mx"; | |
| 143 | − | |
| 144 | − clocks = <&gcc GCC_VIDEO_AXI0_CLK>, | |
| 145 | − <&videocc VIDEO_CC_MVS0C_CLK>, | |
| 146 | − <&videocc VIDEO_CC_MVS0_CLK>; | |
| 147 | − clock-names = "iface", "core", "vcodec0_core"; | |
| 148 | − | |
| 149 | − interconnects = <&gem_noc MASTER_AMPSS_M0 &config_noc SLAVE_VENUS_CFG>, | |
| 150 | − <&mmss_noc MASTER_VIDEO_P0 &mc_virt SLAVE_EBI_CH0>; | |
| 151 | − interconnect-names = "cpu-cfg", "video-mem"; | |
| 152 | − | |
| 153 | − iommus = <&apps_smmu 0x2100 0x0400>; | |
| 154 | − memory-region = <&video_mem>; | |
| 155 | − | |
| 156 | − resets = <&gcc GCC_VIDEO_AXI0_CLK_ARES>, | |
| 157 | − <&videocc VIDEO_CC_MVS0C_CLK_ARES>; | |
| 158 | − reset-names = "bus", "core"; | |
| 159 | − | |
| 160 | − video-decoder { | |
| 161 | − compatible = "venus-decoder"; | |
| 162 | − }; | |
| 163 | − | |
| 164 | − video-encoder { | |
| 165 | − compatible = "venus-encoder"; | |
| 166 | − }; | |
| 105 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 106 | + #include <dt-bindings/clock/qcom,videocc-sm8250.h> | |
| 107 | + #include <dt-bindings/interconnect/qcom,sm8250.h> | |
| 108 | + #include <dt-bindings/clock/qcom,gcc-sm8250.h> | |
| 109 | + #include <dt-bindings/power/qcom-rpmpd.h> | |
| 110 | + | |
| 111 | + venus: video-codec@aa00000 { | |
| 112 | + compatible = "qcom,sm8250-venus"; | |
| 113 | + reg = <0x0aa00000 0xff000>; | |
| 114 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 115 | + power-domains = <&videocc MVS0C_GDSC>, | |
| 116 | + <&videocc MVS0_GDSC>, | |
| 117 | + <&rpmhpd SM8250_MX>; | |
| 118 | + power-domain-names = "venus", "vcodec0", "mx"; | |
| 119 | + | |
| 120 | + clocks = <&gcc GCC_VIDEO_AXI0_CLK>, | |
| 121 | + <&videocc VIDEO_CC_MVS0C_CLK>, | |
| 122 | + <&videocc VIDEO_CC_MVS0_CLK>; | |
| 123 | + clock-names = "iface", "core", "vcodec0_core"; | |
| 124 | + | |
| 125 | + interconnects = <&gem_noc MASTER_AMPSS_M0 &config_noc SLAVE_VENUS_CFG>, | |
| 126 | + <&mmss_noc MASTER_VIDEO_P0 &mc_virt SLAVE_EBI_CH0>; | |
| 127 | + interconnect-names = "cpu-cfg", "video-mem"; | |
| 128 | + | |
| 129 | + iommus = <&apps_smmu 0x2100 0x0400>; | |
| 130 | + memory-region = <&video_mem>; | |
| 131 | + | |
| 132 | + resets = <&gcc GCC_VIDEO_AXI0_CLK_ARES>, | |
| 133 | + <&videocc VIDEO_CC_MVS0C_CLK_ARES>; | |
| 134 | + reset-names = "bus", "core"; | |
| 135 | + | |
| 136 | + video-decoder { | |
| 137 | + compatible = "venus-decoder"; | |
| 138 | + }; | |
| 139 | + | |
| 140 | + video-encoder { | |
| 141 | + compatible = "venus-encoder"; | |
| 167 | 142 | }; |
| 143 | + }; | |
| @@ -0,0 +1,73 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/qcom,venus-common.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Qualcomm SoC Venus Video Encode and Decode Accelerators Common Properties | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Stanimir Varbanov <stanimir.k.varbanov@gmail.com> | |
| 11 | + - Vikash Garodia <quic_vgarodia@quicinc.com> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The Venus IP is a video encode and decode accelerator present | |
| 15 | + on Qualcomm platforms | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + reg: | |
| 19 | + maxItems: 1 | |
| 20 | + | |
| 21 | + clocks: | |
| 22 | + minItems: 3 | |
| 23 | + maxItems: 7 | |
| 24 | + | |
| 25 | + clock-names: | |
| 26 | + minItems: 3 | |
| 27 | + maxItems: 7 | |
| 28 | + | |
| 29 | + firmware-name: | |
| 30 | + maxItems: 1 | |
| 31 | + | |
| 32 | + interrupts: | |
| 33 | + maxItems: 1 | |
| 34 | + | |
| 35 | + iommus: | |
| 36 | + minItems: 1 | |
| 37 | + maxItems: 20 | |
| 38 | + | |
| 39 | + memory-region: | |
| 40 | + maxItems: 1 | |
| 41 | + | |
| 42 | + power-domains: | |
| 43 | + minItems: 1 | |
| 44 | + maxItems: 4 | |
| 45 | + | |
| 46 | + power-domain-names: | |
| 47 | + minItems: 1 | |
| 48 | + maxItems: 4 | |
| 49 | + | |
| 50 | + video-firmware: | |
| 51 | + type: object | |
| 52 | + additionalProperties: false | |
| 53 | + | |
| 54 | + description: | | |
| 55 | + Firmware subnode is needed when the platform does not | |
| 56 | + have TrustZone. | |
| 57 | + | |
| 58 | + properties: | |
| 59 | + iommus: | |
| 60 | + maxItems: 1 | |
| 61 | + | |
| 62 | + required: | |
| 63 | + - iommus | |
| 64 | + | |
| 65 | +required: | |
| 66 | + - reg | |
| 67 | + - clocks | |
| 68 | + - clock-names | |
| 69 | + - interrupts | |
| 70 | + - memory-region | |
| 71 | + - power-domains | |
| 72 | + | |
| 73 | +additionalProperties: true | |
| @@ -18,7 +18,7 @@ properties: · 17 unmodified lines | ||
| 18 | 18 | description: |
| 19 | 19 | Specifies the scancode/key mapping table defined in-kernel for |
| 20 | 20 | the remote controller. |
| 21 | − $ref: '/schemas/types.yaml#/definitions/string' | |
| 21 | + $ref: /schemas/types.yaml#/definitions/string | |
| 22 | 22 | enum: |
| 23 | 23 | - rc-adstech-dvb-t-pci |
| 24 | 24 | - rc-alink-dtu-m |
| @@ -39,6 +39,7 @@ properties: · 14 unmodified lines | ||
| 39 | 39 | - rc-avertv-303 |
| 40 | 40 | - rc-azurewave-ad-tu700 |
| 41 | 41 | - rc-beelink-gs1 |
| 42 | + - rc-beelink-mxiii | |
| 42 | 43 | - rc-behold |
| 43 | 44 | - rc-behold-columbus |
| 44 | 45 | - rc-budget-ci-old |
| @@ -55,6 +56,7 @@ properties: · 10 unmodified lines | ||
| 55 | 56 | - rc-dm1105-nec |
| 56 | 57 | - rc-dntv-live-dvb-t |
| 57 | 58 | - rc-dntv-live-dvbt-pro |
| 59 | + - rc-dreambox | |
| 58 | 60 | - rc-dtt200u |
| 59 | 61 | - rc-dvbsky |
| 60 | 62 | - rc-dvico-mce |
| @@ -31,6 +31,7 @@ properties: · 30 unmodified lines | ||
| 31 | 31 | - renesas,r8a77980-csi2 # R-Car V3H |
| 32 | 32 | - renesas,r8a77990-csi2 # R-Car E3 |
| 33 | 33 | - renesas,r8a779a0-csi2 # R-Car V3U |
| 34 | + - renesas,r8a779g0-csi2 # R-Car V4H | |
| 34 | 35 | |
| 35 | 36 | reg: |
| 36 | 37 | maxItems: 1 |
| @@ -21,15 +21,22 @@ description: | · 20 unmodified lines | ||
| 21 | 21 | |
| 22 | 22 | properties: |
| 23 | 23 | compatible: |
| 24 | − enum: | |
| 25 | − - renesas,fcpv # FCP for VSP | |
| 26 | − - renesas,fcpf # FCP for FDP | |
| 24 | + oneOf: | |
| 25 | + - enum: | |
| 26 | + - renesas,fcpv # FCP for VSP | |
| 27 | + - renesas,fcpf # FCP for FDP | |
| 28 | + - items: | |
| 29 | + - enum: | |
| 30 | + - renesas,r9a07g044-fcpvd # RZ/G2{L,LC} | |
| 31 | + - renesas,r9a07g054-fcpvd # RZ/V2L | |
| 32 | + - const: renesas,fcpv # Generic FCP for VSP fallback | |
| 27 | 33 | |
| 28 | 34 | reg: |
| 29 | 35 | maxItems: 1 |
| 30 | 36 | |
| 31 | − clocks: | |
| 32 | − maxItems: 1 | |
| 37 | + clocks: true | |
| 38 | + | |
| 39 | + clock-names: true | |
| 33 | 40 | |
| 34 | 41 | iommus: |
| 35 | 42 | maxItems: 1 |
| @@ -49,6 +56,34 @@ required: · 13 unmodified lines | ||
| 49 | 56 | |
| 50 | 57 | additionalProperties: false |
| 51 | 58 | |
| 59 | +allOf: | |
| 60 | + - if: | |
| 61 | + properties: | |
| 62 | + compatible: | |
| 63 | + contains: | |
| 64 | + enum: | |
| 65 | + - renesas,r9a07g044-fcpvd | |
| 66 | + - renesas,r9a07g054-fcpvd | |
| 67 | + then: | |
| 68 | + properties: | |
| 69 | + clocks: | |
| 70 | + items: | |
| 71 | + - description: Main clock | |
| 72 | + - description: Register access clock | |
| 73 | + - description: Video clock | |
| 74 | + clock-names: | |
| 75 | + items: | |
| 76 | + - const: aclk | |
| 77 | + - const: pclk | |
| 78 | + - const: vclk | |
| 79 | + required: | |
| 80 | + - clock-names | |
| 81 | + else: | |
| 82 | + properties: | |
| 83 | + clocks: | |
| 84 | + maxItems: 1 | |
| 85 | + clock-names: false | |
| 86 | + | |
| 52 | 87 | examples: |
| 53 | 88 | # R8A7795 (R-Car H3) FCP for VSP-D1 |
| 54 | 89 | - | |
| @@ -21,6 +21,7 @@ properties: · 20 unmodified lines | ||
| 21 | 21 | items: |
| 22 | 22 | - enum: |
| 23 | 23 | - renesas,r8a779a0-isp # V3U |
| 24 | + - renesas,r8a779g0-isp # V4H | |
| 24 | 25 | reg: |
| 25 | 26 | maxItems: 1 |
| 26 | 27 | |
| @@ -53,6 +53,7 @@ properties: · 52 unmodified lines | ||
| 53 | 53 | - renesas,vin-r8a77990 # R-Car E3 |
| 54 | 54 | - renesas,vin-r8a77995 # R-Car D3 |
| 55 | 55 | - renesas,vin-r8a779a0 # R-Car V3U |
| 56 | + - renesas,vin-r8a779g0 # R-Car V4H | |
| 56 | 57 | |
| 57 | 58 | reg: |
| 58 | 59 | maxItems: 1 |
| @@ -16,10 +16,15 @@ description: · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | properties: |
| 18 | 18 | compatible: |
| 19 | − enum: | |
| 20 | − - renesas,r9a07g044-vsp2 # RZ/G2L | |
| 21 | − - renesas,vsp1 # R-Car Gen2 and RZ/G1 | |
| 22 | − - renesas,vsp2 # R-Car Gen3 and RZ/G2 | |
| 19 | + oneOf: | |
| 20 | + - enum: | |
| 21 | + - renesas,r9a07g044-vsp2 # RZ/G2L | |
| 22 | + - renesas,vsp1 # R-Car Gen2 and RZ/G1 | |
| 23 | + - renesas,vsp2 # R-Car Gen3 and RZ/G2 | |
| 24 | + - items: | |
| 25 | + - enum: | |
| 26 | + - renesas,r9a07g054-vsp2 # RZ/V2L | |
| 27 | + - const: renesas,r9a07g044-vsp2 # RZ/G2L fallback | |
| 23 | 28 | |
| 24 | 29 | reg: |
| 25 | 30 | maxItems: 1 |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/rockchip,rk3568-vepu.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/rockchip,rk3568-vepu.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Hantro G1 VPU encoders implemented on Rockchip SoCs |
| 9 | 9 | |
| @@ -212,12 +212,19 @@ examples: · 211 unmodified lines | ||
| 212 | 212 | compatible = "ovti,ov2685"; |
| 213 | 213 | reg = <0x3c>; |
| 214 | 214 | |
| 215 | − port { | |
| 216 | − ucam_out: endpoint { | |
| 217 | − remote-endpoint = <&mipi_in_ucam>; | |
| 218 | − data-lanes = <1>; | |
| 219 | − }; | |
| 220 | − }; | |
| 215 | + clocks = <&cru SCLK_TESTCLKOUT1>; | |
| 216 | + clock-names = "xvclk"; | |
| 217 | + | |
| 218 | + avdd-supply = <&pp2800_cam>; | |
| 219 | + dovdd-supply = <&pp1800>; | |
| 220 | + dvdd-supply = <&pp1800>; | |
| 221 | + | |
| 222 | + port { | |
| 223 | + ucam_out: endpoint { | |
| 224 | + remote-endpoint = <&mipi_in_ucam>; | |
| 225 | + data-lanes = <1>; | |
| 226 | + }; | |
| 227 | + }; | |
| 221 | 228 | }; |
| 222 | 229 | }; |
| 223 | 230 | }; |
| @@ -2,8 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | %YAML 1.2 |
| 4 | 4 | --- |
| 5 | −$id: "http://devicetree.org/schemas/media/rockchip-vpu.yaml#" | |
| 6 | −$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 5 | +$id: http://devicetree.org/schemas/media/rockchip-vpu.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | 7 | |
| 8 | 8 | title: Hantro G1 VPU codecs implemented on Rockchip SoCs |
| 9 | 9 | |
| @@ -0,0 +1,170 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/samsung,exynos4210-csis.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung S5P/Exynos SoC series MIPI CSI-2 receiver (MIPI CSIS) | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + - Sylwester Nawrocki <s.nawrocki@samsung.com> | |
| 12 | + | |
| 13 | +properties: | |
| 14 | + compatible: | |
| 15 | + enum: | |
| 16 | + - samsung,s5pv210-csis | |
| 17 | + - samsung,exynos4210-csis | |
| 18 | + - samsung,exynos4212-csis | |
| 19 | + - samsung,exynos5250-csis | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + '#address-cells': | |
| 25 | + const: 1 | |
| 26 | + | |
| 27 | + '#size-cells': | |
| 28 | + const: 0 | |
| 29 | + | |
| 30 | + bus-width: | |
| 31 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 32 | + enum: [2, 4] | |
| 33 | + description: | |
| 34 | + Number of data lines supported. | |
| 35 | + | |
| 36 | + clocks: | |
| 37 | + maxItems: 2 | |
| 38 | + | |
| 39 | + clock-names: | |
| 40 | + items: | |
| 41 | + - const: csis | |
| 42 | + - const: sclk_csis | |
| 43 | + | |
| 44 | + clock-frequency: | |
| 45 | + default: 166000000 | |
| 46 | + description: | |
| 47 | + The IP's main (system bus) clock frequency in Hz. | |
| 48 | + | |
| 49 | + interrupts: | |
| 50 | + maxItems: 1 | |
| 51 | + | |
| 52 | + phys: | |
| 53 | + maxItems: 1 | |
| 54 | + | |
| 55 | + phy-names: | |
| 56 | + items: | |
| 57 | + - const: csis | |
| 58 | + | |
| 59 | + power-domains: | |
| 60 | + maxItems: 1 | |
| 61 | + | |
| 62 | + vddio-supply: | |
| 63 | + description: MIPI CSIS I/O and PLL voltage supply (e.g. 1.8V). | |
| 64 | + | |
| 65 | + vddcore-supply: | |
| 66 | + description: MIPI CSIS Core voltage supply (e.g. 1.1V). | |
| 67 | + | |
| 68 | +patternProperties: | |
| 69 | + "^port@[34]$": | |
| 70 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 71 | + additionalProperties: false | |
| 72 | + description: | |
| 73 | + Camera input port. | |
| 74 | + | |
| 75 | + properties: | |
| 76 | + reg: | |
| 77 | + enum: [3, 4] | |
| 78 | + | |
| 79 | + endpoint: | |
| 80 | + $ref: video-interfaces.yaml# | |
| 81 | + unevaluatedProperties: false | |
| 82 | + | |
| 83 | + properties: | |
| 84 | + data-lanes: | |
| 85 | + minItems: 1 | |
| 86 | + maxItems: 4 | |
| 87 | + | |
| 88 | + samsung,csis-hs-settle: | |
| 89 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 90 | + description: Differential receiver (HS-RX) settle time. | |
| 91 | + | |
| 92 | + samsung,csis-wclk: | |
| 93 | + type: boolean | |
| 94 | + description: | |
| 95 | + CSI-2 wrapper clock selection. If this property is present external clock | |
| 96 | + from CMU will be used, or the bus clock if it's not specified. | |
| 97 | + | |
| 98 | + required: | |
| 99 | + - data-lanes | |
| 100 | + | |
| 101 | + required: | |
| 102 | + - reg | |
| 103 | + | |
| 104 | +required: | |
| 105 | + - compatible | |
| 106 | + - reg | |
| 107 | + - bus-width | |
| 108 | + - clocks | |
| 109 | + - clock-names | |
| 110 | + - interrupts | |
| 111 | + - vddio-supply | |
| 112 | + - vddcore-supply | |
| 113 | + | |
| 114 | +anyOf: | |
| 115 | + - required: | |
| 116 | + - port@3 | |
| 117 | + - required: | |
| 118 | + - port@4 | |
| 119 | + | |
| 120 | +allOf: | |
| 121 | + - if: | |
| 122 | + required: | |
| 123 | + - samsung,isp-wb | |
| 124 | + then: | |
| 125 | + required: | |
| 126 | + - samsung,sysreg | |
| 127 | + | |
| 128 | +additionalProperties: false | |
| 129 | + | |
| 130 | +examples: | |
| 131 | + - | | |
| 132 | + #include <dt-bindings/clock/exynos4.h> | |
| 133 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 134 | + | |
| 135 | + csis@11890000 { | |
| 136 | + compatible = "samsung,exynos4210-csis"; | |
| 137 | + reg = <0x11890000 0x4000>; | |
| 138 | + clocks = <&clock CLK_CSIS1>, | |
| 139 | + <&clock CLK_SCLK_CSIS1>; | |
| 140 | + clock-names = "csis", "sclk_csis"; | |
| 141 | + assigned-clocks = <&clock CLK_MOUT_CSIS1>, | |
| 142 | + <&clock CLK_SCLK_CSIS1>; | |
| 143 | + assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>; | |
| 144 | + assigned-clock-rates = <0>, <176000000>; | |
| 145 | + | |
| 146 | + interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>; | |
| 147 | + | |
| 148 | + bus-width = <2>; | |
| 149 | + power-domains = <&pd_cam>; | |
| 150 | + phys = <&mipi_phy 2>; | |
| 151 | + phy-names = "csis"; | |
| 152 | + | |
| 153 | + vddcore-supply = <&ldo8_reg>; | |
| 154 | + vddio-supply = <&ldo10_reg>; | |
| 155 | + | |
| 156 | + #address-cells = <1>; | |
| 157 | + #size-cells = <0>; | |
| 158 | + | |
| 159 | + /* Camera D (4) MIPI CSI-2 (CSIS1) */ | |
| 160 | + port@4 { | |
| 161 | + reg = <4>; | |
| 162 | + | |
| 163 | + endpoint { | |
| 164 | + remote-endpoint = <&is_s5k6a3_ep>; | |
| 165 | + data-lanes = <1>; | |
| 166 | + samsung,csis-hs-settle = <18>; | |
| 167 | + samsung,csis-wclk; | |
| 168 | + }; | |
| 169 | + }; | |
| 170 | + }; | |
| @@ -0,0 +1,152 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/samsung,exynos4210-fimc.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung S5P/Exynos SoC Fully Integrated Mobile Camera | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + - Sylwester Nawrocki <s.nawrocki@samsung.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + Each FIMC device should have an alias in the aliases node, in the form of | |
| 15 | + fimc<n>, where <n> is an integer specifying the IP block instance. | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + enum: | |
| 20 | + - samsung,exynos4210-fimc | |
| 21 | + - samsung,exynos4212-fimc | |
| 22 | + - samsung,s5pv210-fimc | |
| 23 | + | |
| 24 | + reg: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + clocks: | |
| 28 | + maxItems: 2 | |
| 29 | + | |
| 30 | + clock-names: | |
| 31 | + items: | |
| 32 | + - const: fimc | |
| 33 | + - const: sclk_fimc | |
| 34 | + | |
| 35 | + clock-frequency: | |
| 36 | + description: | |
| 37 | + Maximum FIMC local clock (LCLK) frequency. | |
| 38 | + | |
| 39 | + interrupts: | |
| 40 | + maxItems: 1 | |
| 41 | + | |
| 42 | + iommus: | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 45 | + power-domains: | |
| 46 | + maxItems: 1 | |
| 47 | + | |
| 48 | + samsung,cam-if: | |
| 49 | + type: boolean | |
| 50 | + description: | |
| 51 | + The FIMC IP block includes the camera input interface. | |
| 52 | + | |
| 53 | + samsung,isp-wb: | |
| 54 | + type: boolean | |
| 55 | + description: | | |
| 56 | + The FIMC IP block has the ISP writeback input. | |
| 57 | + | |
| 58 | + samsung,lcd-wb: | |
| 59 | + type: boolean | |
| 60 | + description: | | |
| 61 | + The FIMC IP block has the LCD writeback input. | |
| 62 | + | |
| 63 | + samsung,mainscaler-ext: | |
| 64 | + type: boolean | |
| 65 | + description: | |
| 66 | + FIMC IP supports extended image size and has CIEXTEN register. | |
| 67 | + | |
| 68 | + samsung,min-pix-alignment: | |
| 69 | + $ref: /schemas/types.yaml#/definitions/uint32-array | |
| 70 | + items: | |
| 71 | + - description: Minimum supported image height alignment. | |
| 72 | + - description: Horizontal image offset. | |
| 73 | + description: | |
| 74 | + The values are in pixels and default is <2 1>. | |
| 75 | + | |
| 76 | + samsung,min-pix-sizes: | |
| 77 | + $ref: /schemas/types.yaml#/definitions/uint32-array | |
| 78 | + maxItems: 2 | |
| 79 | + description: | | |
| 80 | + An array specyfing minimum image size in pixels at the FIMC input and | |
| 81 | + output DMA, in the first and second cell respectively. Default value | |
| 82 | + is <16 16>. | |
| 83 | + | |
| 84 | + samsung,pix-limits: | |
| 85 | + $ref: /schemas/types.yaml#/definitions/uint32-array | |
| 86 | + maxItems: 4 | |
| 87 | + description: | | |
| 88 | + An array of maximum supported image sizes in pixels, for details refer to | |
| 89 | + Table 2-1 in the S5PV210 SoC User Manual. The meaning of each cell is as | |
| 90 | + follows: | |
| 91 | + 0 - scaler input horizontal size | |
| 92 | + 1 - input horizontal size for the scaler bypassed | |
| 93 | + 2 - REAL_WIDTH without input rotation | |
| 94 | + 3 - REAL_HEIGHT with input rotation | |
| 95 | + | |
| 96 | + samsung,rotators: | |
| 97 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 98 | + default: 0x11 | |
| 99 | + description: | | |
| 100 | + A bitmask specifying whether this IP has the input and the output | |
| 101 | + rotator. Bits 4 and 0 correspond to input and output rotator | |
| 102 | + respectively. If a rotator is present its corresponding bit should be | |
| 103 | + set. | |
| 104 | + | |
| 105 | + samsung,sysreg: | |
| 106 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 107 | + description: | |
| 108 | + System Registers (SYSREG) node. | |
| 109 | + | |
| 110 | +required: | |
| 111 | + - compatible | |
| 112 | + - reg | |
| 113 | + - clocks | |
| 114 | + - clock-names | |
| 115 | + - samsung,pix-limits | |
| 116 | + | |
| 117 | +allOf: | |
| 118 | + - if: | |
| 119 | + required: | |
| 120 | + - samsung,isp-wb | |
| 121 | + then: | |
| 122 | + required: | |
| 123 | + - samsung,sysreg | |
| 124 | + | |
| 125 | +additionalProperties: false | |
| 126 | + | |
| 127 | +examples: | |
| 128 | + - | | |
| 129 | + #include <dt-bindings/clock/exynos4.h> | |
| 130 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 131 | + | |
| 132 | + fimc@11800000 { | |
| 133 | + compatible = "samsung,exynos4212-fimc"; | |
| 134 | + reg = <0x11800000 0x1000>; | |
| 135 | + clocks = <&clock CLK_FIMC0>, | |
| 136 | + <&clock CLK_SCLK_FIMC0>; | |
| 137 | + clock-names = "fimc", "sclk_fimc"; | |
| 138 | + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; | |
| 139 | + iommus = <&sysmmu_fimc0>; | |
| 140 | + power-domains = <&pd_cam>; | |
| 141 | + samsung,sysreg = <&sys_reg>; | |
| 142 | + | |
| 143 | + samsung,pix-limits = <4224 8192 1920 4224>; | |
| 144 | + samsung,mainscaler-ext; | |
| 145 | + samsung,isp-wb; | |
| 146 | + samsung,cam-if; | |
| 147 | + | |
| 148 | + assigned-clocks = <&clock CLK_MOUT_FIMC0>, | |
| 149 | + <&clock CLK_SCLK_FIMC0>; | |
| 150 | + assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>; | |
| 151 | + assigned-clock-rates = <0>, <176000000>; | |
| 152 | + }; | |
| @@ -0,0 +1,220 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/samsung,exynos4212-fimc-is.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung Exynos4212/4412 SoC Imaging Subsystem (FIMC-IS) | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + - Sylwester Nawrocki <s.nawrocki@samsung.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + The FIMC-IS is a subsystem for processing image signal from an image sensor. | |
| 15 | + The Exynos4x12 SoC series FIMC-IS V1.5 comprises of a dedicated ARM Cortex-A5 | |
| 16 | + processor, ISP, DRC and FD IP blocks and peripheral devices such as UART, I2C | |
| 17 | + and SPI bus controllers, PWM and ADC. | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + enum: | |
| 22 | + - samsung,exynos4212-fimc-is | |
| 23 | + | |
| 24 | + reg: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + ranges: true | |
| 28 | + | |
| 29 | + '#address-cells': | |
| 30 | + const: 1 | |
| 31 | + | |
| 32 | + '#size-cells': | |
| 33 | + const: 1 | |
| 34 | + | |
| 35 | + clocks: | |
| 36 | + maxItems: 21 | |
| 37 | + | |
| 38 | + clock-names: | |
| 39 | + items: | |
| 40 | + - const: lite0 | |
| 41 | + - const: lite1 | |
| 42 | + - const: ppmuispx | |
| 43 | + - const: ppmuispmx | |
| 44 | + - const: isp | |
| 45 | + - const: drc | |
| 46 | + - const: fd | |
| 47 | + - const: mcuisp | |
| 48 | + - const: gicisp | |
| 49 | + - const: mcuctl_isp | |
| 50 | + - const: pwm_isp | |
| 51 | + - const: ispdiv0 | |
| 52 | + - const: ispdiv1 | |
| 53 | + - const: mcuispdiv0 | |
| 54 | + - const: mcuispdiv1 | |
| 55 | + - const: mpll | |
| 56 | + - const: aclk200 | |
| 57 | + - const: aclk400mcuisp | |
| 58 | + - const: div_aclk200 | |
| 59 | + - const: div_aclk400mcuisp | |
| 60 | + - const: uart | |
| 61 | + | |
| 62 | + interrupts: | |
| 63 | + maxItems: 2 | |
| 64 | + | |
| 65 | + iommus: | |
| 66 | + maxItems: 4 | |
| 67 | + | |
| 68 | + iommu-names: | |
| 69 | + items: | |
| 70 | + - const: isp | |
| 71 | + - const: drc | |
| 72 | + - const: fd | |
| 73 | + - const: mcuctl | |
| 74 | + | |
| 75 | + power-domains: | |
| 76 | + maxItems: 1 | |
| 77 | + | |
| 78 | +patternProperties: | |
| 79 | + "^pmu@[0-9a-f]+$": | |
| 80 | + type: object | |
| 81 | + additionalProperties: false | |
| 82 | + description: | |
| 83 | + Node representing the SoC's Power Management Unit (duplicated with the | |
| 84 | + correct PMU node in the SoC). | |
| 85 | + | |
| 86 | + properties: | |
| 87 | + reg: | |
| 88 | + maxItems: 1 | |
| 89 | + | |
| 90 | + required: | |
| 91 | + - reg | |
| 92 | + | |
| 93 | + "^i2c-isp@[0-9a-f]+$": | |
| 94 | + type: object | |
| 95 | + $ref: /schemas/i2c/i2c-controller.yaml# | |
| 96 | + unevaluatedProperties: false | |
| 97 | + description: | |
| 98 | + ISP I2C bus controller | |
| 99 | + | |
| 100 | + properties: | |
| 101 | + compatible: | |
| 102 | + const: samsung,exynos4212-i2c-isp | |
| 103 | + | |
| 104 | + reg: | |
| 105 | + maxItems: 1 | |
| 106 | + | |
| 107 | + | |
| 108 | + clocks: | |
| 109 | + maxItems: 1 | |
| 110 | + | |
| 111 | + clock-names: | |
| 112 | + items: | |
| 113 | + - const: i2c_isp | |
| 114 | + | |
| 115 | + pinctrl-0: true | |
| 116 | + pinctrl-names: | |
| 117 | + items: | |
| 118 | + - const: default | |
| 119 | + | |
| 120 | + required: | |
| 121 | + - compatible | |
| 122 | + - reg | |
| 123 | + - clocks | |
| 124 | + - clock-names | |
| 125 | + | |
| 126 | +required: | |
| 127 | + - compatible | |
| 128 | + - reg | |
| 129 | + - '#address-cells' | |
| 130 | + - clocks | |
| 131 | + - clock-names | |
| 132 | + - interrupts | |
| 133 | + - ranges | |
| 134 | + - '#size-cells' | |
| 135 | + | |
| 136 | +additionalProperties: false | |
| 137 | + | |
| 138 | +examples: | |
| 139 | + - | | |
| 140 | + #include <dt-bindings/clock/exynos4.h> | |
| 141 | + #include <dt-bindings/gpio/gpio.h> | |
| 142 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 143 | + | |
| 144 | + fimc-is@12000000 { | |
| 145 | + compatible = "samsung,exynos4212-fimc-is"; | |
| 146 | + reg = <0x12000000 0x260000>; | |
| 147 | + interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, | |
| 148 | + <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; | |
| 149 | + clocks = <&isp_clock CLK_ISP_FIMC_LITE0>, | |
| 150 | + <&isp_clock CLK_ISP_FIMC_LITE1>, | |
| 151 | + <&isp_clock CLK_ISP_PPMUISPX>, | |
| 152 | + <&isp_clock CLK_ISP_PPMUISPMX>, | |
| 153 | + <&isp_clock CLK_ISP_FIMC_ISP>, | |
| 154 | + <&isp_clock CLK_ISP_FIMC_DRC>, | |
| 155 | + <&isp_clock CLK_ISP_FIMC_FD>, | |
| 156 | + <&isp_clock CLK_ISP_MCUISP>, | |
| 157 | + <&isp_clock CLK_ISP_GICISP>, | |
| 158 | + <&isp_clock CLK_ISP_MCUCTL_ISP>, | |
| 159 | + <&isp_clock CLK_ISP_PWM_ISP>, | |
| 160 | + <&isp_clock CLK_ISP_DIV_ISP0>, | |
| 161 | + <&isp_clock CLK_ISP_DIV_ISP1>, | |
| 162 | + <&isp_clock CLK_ISP_DIV_MCUISP0>, | |
| 163 | + <&isp_clock CLK_ISP_DIV_MCUISP1>, | |
| 164 | + <&clock CLK_MOUT_MPLL_USER_T>, | |
| 165 | + <&clock CLK_ACLK200>, | |
| 166 | + <&clock CLK_ACLK400_MCUISP>, | |
| 167 | + <&clock CLK_DIV_ACLK200>, | |
| 168 | + <&clock CLK_DIV_ACLK400_MCUISP>, | |
| 169 | + <&clock CLK_UART_ISP_SCLK>; | |
| 170 | + clock-names = "lite0", "lite1", "ppmuispx", | |
| 171 | + "ppmuispmx", "isp", | |
| 172 | + "drc", "fd", "mcuisp", | |
| 173 | + "gicisp", "mcuctl_isp", "pwm_isp", | |
| 174 | + "ispdiv0", "ispdiv1", "mcuispdiv0", | |
| 175 | + "mcuispdiv1", "mpll", "aclk200", | |
| 176 | + "aclk400mcuisp", "div_aclk200", | |
| 177 | + "div_aclk400mcuisp", "uart"; | |
| 178 | + iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>, | |
| 179 | + <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>; | |
| 180 | + iommu-names = "isp", "drc", "fd", "mcuctl"; | |
| 181 | + power-domains = <&pd_isp>; | |
| 182 | + | |
| 183 | + #address-cells = <1>; | |
| 184 | + #size-cells = <1>; | |
| 185 | + ranges; | |
| 186 | + | |
| 187 | + pmu@10020000 { | |
| 188 | + reg = <0x10020000 0x3000>; | |
| 189 | + }; | |
| 190 | + | |
| 191 | + i2c-isp@12140000 { | |
| 192 | + compatible = "samsung,exynos4212-i2c-isp"; | |
| 193 | + reg = <0x12140000 0x100>; | |
| 194 | + clocks = <&isp_clock CLK_ISP_I2C1_ISP>; | |
| 195 | + clock-names = "i2c_isp"; | |
| 196 | + pinctrl-0 = <&fimc_is_i2c1>; | |
| 197 | + pinctrl-names = "default"; | |
| 198 | + #address-cells = <1>; | |
| 199 | + #size-cells = <0>; | |
| 200 | + | |
| 201 | + image-sensor@10 { | |
| 202 | + compatible = "samsung,s5k6a3"; | |
| 203 | + reg = <0x10>; | |
| 204 | + svdda-supply = <&cam_io_reg>; | |
| 205 | + svddio-supply = <&ldo19_reg>; | |
| 206 | + afvdd-supply = <&ldo19_reg>; | |
| 207 | + clock-frequency = <24000000>; | |
| 208 | + clocks = <&camera 1>; | |
| 209 | + clock-names = "extclk"; | |
| 210 | + gpios = <&gpm1 6 GPIO_ACTIVE_LOW>; | |
| 211 | + | |
| 212 | + port { | |
| 213 | + endpoint { | |
| 214 | + remote-endpoint = <&csis1_ep>; | |
| 215 | + data-lanes = <1>; | |
| 216 | + }; | |
| 217 | + }; | |
| 218 | + }; | |
| 219 | + }; | |
| 220 | + }; | |
| @@ -0,0 +1,63 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/samsung,exynos4212-fimc-lite.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung Exynos SoC series camera host interface (FIMC-LITE) | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + - Sylwester Nawrocki <s.nawrocki@samsung.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + Each FIMC device should have an alias in the aliases node, in the form of | |
| 15 | + fimc-lite<n>, where <n> is an integer specifying the IP block instance. | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + enum: | |
| 20 | + - samsung,exynos4212-fimc-lite | |
| 21 | + - samsung,exynos5250-fimc-lite | |
| 22 | + | |
| 23 | + reg: | |
| 24 | + maxItems: 1 | |
| 25 | + | |
| 26 | + clocks: | |
| 27 | + maxItems: 1 | |
| 28 | + | |
| 29 | + clock-names: | |
| 30 | + items: | |
| 31 | + - const: flite | |
| 32 | + | |
| 33 | + interrupts: | |
| 34 | + maxItems: 1 | |
| 35 | + | |
| 36 | + iommus: | |
| 37 | + maxItems: 1 | |
| 38 | + | |
| 39 | + power-domains: | |
| 40 | + maxItems: 1 | |
| 41 | + | |
| 42 | +required: | |
| 43 | + - compatible | |
| 44 | + - reg | |
| 45 | + - clocks | |
| 46 | + - clock-names | |
| 47 | + - interrupts | |
| 48 | + | |
| 49 | +additionalProperties: false | |
| 50 | + | |
| 51 | +examples: | |
| 52 | + - | | |
| 53 | + #include <dt-bindings/clock/exynos4.h> | |
| 54 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 55 | + fimc-lite@12390000 { | |
| 56 | + compatible = "samsung,exynos4212-fimc-lite"; | |
| 57 | + reg = <0x12390000 0x1000>; | |
| 58 | + clocks = <&isp_clock CLK_ISP_FIMC_LITE0>; | |
| 59 | + clock-names = "flite"; | |
| 60 | + interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; | |
| 61 | + power-domains = <&pd_isp>; | |
| 62 | + iommus = <&sysmmu_fimc_lite0>; | |
| 63 | + }; | |
| @@ -0,0 +1,279 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/samsung,fimc.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung S5P/Exynos SoC Camera Subsystem (FIMC) | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + - Sylwester Nawrocki <s.nawrocki@samsung.com> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The S5P/Exynos SoC Camera subsystem comprises of multiple sub-devices | |
| 15 | + represented by separate device tree nodes. Currently this includes: Fully | |
| 16 | + Integrated Mobile Camera (FIMC, in the S5P SoCs series known as CAMIF), MIPI | |
| 17 | + CSIS, FIMC-LITE and FIMC-IS (ISP). | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + const: samsung,fimc | |
| 22 | + | |
| 23 | + ranges: true | |
| 24 | + | |
| 25 | + '#address-cells': | |
| 26 | + const: 1 | |
| 27 | + | |
| 28 | + '#size-cells': | |
| 29 | + const: 1 | |
| 30 | + | |
| 31 | + '#clock-cells': | |
| 32 | + const: 1 | |
| 33 | + description: | | |
| 34 | + The clock specifier cell stores an index of a clock: 0, 1 for | |
| 35 | + CAM_A_CLKOUT, CAM_B_CLKOUT clocks respectively. | |
| 36 | + | |
| 37 | + clocks: | |
| 38 | + minItems: 2 | |
| 39 | + maxItems: 4 | |
| 40 | + | |
| 41 | + clock-names: | |
| 42 | + minItems: 2 | |
| 43 | + items: | |
| 44 | + - const: sclk_cam0 | |
| 45 | + - const: sclk_cam1 | |
| 46 | + - const: pxl_async0 | |
| 47 | + - const: pxl_async1 | |
| 48 | + | |
| 49 | + clock-output-names: | |
| 50 | + maxItems: 2 | |
| 51 | + | |
| 52 | + parallel-ports: | |
| 53 | + $ref: /schemas/graph.yaml#/properties/ports | |
| 54 | + description: | |
| 55 | + Active parallel video input ports. | |
| 56 | + | |
| 57 | + patternProperties: | |
| 58 | + "^port@[01]$": | |
| 59 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 60 | + description: | |
| 61 | + Camera A and camera B inputs. | |
| 62 | + | |
| 63 | + properties: | |
| 64 | + endpoint: | |
| 65 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 66 | + unevaluatedProperties: false | |
| 67 | + | |
| 68 | + pinctrl-names: | |
| 69 | + minItems: 1 | |
| 70 | + items: | |
| 71 | + - const: default | |
| 72 | + - const: idle | |
| 73 | + - const: active_a | |
| 74 | + - const: active_b | |
| 75 | + | |
| 76 | +patternProperties: | |
| 77 | + "^csis@[0-9a-f]+$": | |
| 78 | + type: object | |
| 79 | + $ref: samsung,exynos4210-csis.yaml# | |
| 80 | + description: MIPI CSI-2 receiver. | |
| 81 | + | |
| 82 | + "^fimc@[0-9a-f]+$": | |
| 83 | + type: object | |
| 84 | + $ref: samsung,exynos4210-fimc.yaml# | |
| 85 | + description: Fully Integrated Mobile Camera. | |
| 86 | + | |
| 87 | + "^fimc-is@[0-9a-f]+$": | |
| 88 | + type: object | |
| 89 | + $ref: samsung,exynos4212-fimc-is.yaml# | |
| 90 | + description: Imaging Subsystem (FIMC-IS). | |
| 91 | + | |
| 92 | + "^fimc-lite@[0-9a-f]+$": | |
| 93 | + type: object | |
| 94 | + $ref: samsung,exynos4212-fimc-lite.yaml# | |
| 95 | + description: Camera host interface (FIMC-LITE). | |
| 96 | + | |
| 97 | +required: | |
| 98 | + - compatible | |
| 99 | + - '#address-cells' | |
| 100 | + - '#clock-cells' | |
| 101 | + - clocks | |
| 102 | + - clock-names | |
| 103 | + - clock-output-names | |
| 104 | + - ranges | |
| 105 | + - '#size-cells' | |
| 106 | + | |
| 107 | +additionalProperties: false | |
| 108 | + | |
| 109 | +examples: | |
| 110 | + - | | |
| 111 | + #include <dt-bindings/clock/exynos4.h> | |
| 112 | + #include <dt-bindings/gpio/gpio.h> | |
| 113 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 114 | + | |
| 115 | + camera@11800000 { | |
| 116 | + compatible = "samsung,fimc"; | |
| 117 | + #clock-cells = <1>; | |
| 118 | + #address-cells = <1>; | |
| 119 | + #size-cells = <1>; | |
| 120 | + ranges = <0x0 0x0 0x18000000>; | |
| 121 | + | |
| 122 | + clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>, | |
| 123 | + <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>; | |
| 124 | + clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1"; | |
| 125 | + clock-output-names = "cam_a_clkout", "cam_b_clkout"; | |
| 126 | + | |
| 127 | + assigned-clocks = <&clock CLK_MOUT_CAM0>, | |
| 128 | + <&clock CLK_MOUT_CAM1>; | |
| 129 | + assigned-clock-parents = <&clock CLK_XUSBXTI>, | |
| 130 | + <&clock CLK_XUSBXTI>; | |
| 131 | + | |
| 132 | + pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>; | |
| 133 | + pinctrl-names = "default"; | |
| 134 | + | |
| 135 | + fimc@11800000 { | |
| 136 | + compatible = "samsung,exynos4212-fimc"; | |
| 137 | + reg = <0x11800000 0x1000>; | |
| 138 | + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; | |
| 139 | + clocks = <&clock CLK_FIMC0>, | |
| 140 | + <&clock CLK_SCLK_FIMC0>; | |
| 141 | + clock-names = "fimc", "sclk_fimc"; | |
| 142 | + power-domains = <&pd_cam>; | |
| 143 | + samsung,sysreg = <&sys_reg>; | |
| 144 | + iommus = <&sysmmu_fimc0>; | |
| 145 | + | |
| 146 | + samsung,pix-limits = <4224 8192 1920 4224>; | |
| 147 | + samsung,mainscaler-ext; | |
| 148 | + samsung,isp-wb; | |
| 149 | + samsung,cam-if; | |
| 150 | + }; | |
| 151 | + | |
| 152 | + /* ... FIMC 1-3 */ | |
| 153 | + | |
| 154 | + csis@11880000 { | |
| 155 | + compatible = "samsung,exynos4210-csis"; | |
| 156 | + reg = <0x11880000 0x4000>; | |
| 157 | + interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>; | |
| 158 | + clocks = <&clock CLK_CSIS0>, | |
| 159 | + <&clock CLK_SCLK_CSIS0>; | |
| 160 | + clock-names = "csis", "sclk_csis"; | |
| 161 | + assigned-clocks = <&clock CLK_MOUT_CSIS0>, | |
| 162 | + <&clock CLK_SCLK_CSIS0>; | |
| 163 | + assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>; | |
| 164 | + assigned-clock-rates = <0>, <176000000>; | |
| 165 | + | |
| 166 | + bus-width = <4>; | |
| 167 | + power-domains = <&pd_cam>; | |
| 168 | + phys = <&mipi_phy 0>; | |
| 169 | + phy-names = "csis"; | |
| 170 | + #address-cells = <1>; | |
| 171 | + #size-cells = <0>; | |
| 172 | + | |
| 173 | + vddcore-supply = <&ldo8_reg>; | |
| 174 | + vddio-supply = <&ldo10_reg>; | |
| 175 | + | |
| 176 | + /* Camera C (3) MIPI CSI-2 (CSIS0) */ | |
| 177 | + port@3 { | |
| 178 | + reg = <3>; | |
| 179 | + endpoint { | |
| 180 | + remote-endpoint = <&s5c73m3_ep>; | |
| 181 | + data-lanes = <1 2 3 4>; | |
| 182 | + samsung,csis-hs-settle = <12>; | |
| 183 | + }; | |
| 184 | + }; | |
| 185 | + }; | |
| 186 | + | |
| 187 | + /* ... CSIS 1 */ | |
| 188 | + | |
| 189 | + fimc-lite@12390000 { | |
| 190 | + compatible = "samsung,exynos4212-fimc-lite"; | |
| 191 | + reg = <0x12390000 0x1000>; | |
| 192 | + interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>; | |
| 193 | + power-domains = <&pd_isp>; | |
| 194 | + clocks = <&isp_clock CLK_ISP_FIMC_LITE0>; | |
| 195 | + clock-names = "flite"; | |
| 196 | + iommus = <&sysmmu_fimc_lite0>; | |
| 197 | + }; | |
| 198 | + | |
| 199 | + /* ... FIMC-LITE 1 */ | |
| 200 | + | |
| 201 | + fimc-is@12000000 { | |
| 202 | + compatible = "samsung,exynos4212-fimc-is"; | |
| 203 | + reg = <0x12000000 0x260000>; | |
| 204 | + interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>, | |
| 205 | + <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; | |
| 206 | + clocks = <&isp_clock CLK_ISP_FIMC_LITE0>, | |
| 207 | + <&isp_clock CLK_ISP_FIMC_LITE1>, | |
| 208 | + <&isp_clock CLK_ISP_PPMUISPX>, | |
| 209 | + <&isp_clock CLK_ISP_PPMUISPMX>, | |
| 210 | + <&isp_clock CLK_ISP_FIMC_ISP>, | |
| 211 | + <&isp_clock CLK_ISP_FIMC_DRC>, | |
| 212 | + <&isp_clock CLK_ISP_FIMC_FD>, | |
| 213 | + <&isp_clock CLK_ISP_MCUISP>, | |
| 214 | + <&isp_clock CLK_ISP_GICISP>, | |
| 215 | + <&isp_clock CLK_ISP_MCUCTL_ISP>, | |
| 216 | + <&isp_clock CLK_ISP_PWM_ISP>, | |
| 217 | + <&isp_clock CLK_ISP_DIV_ISP0>, | |
| 218 | + <&isp_clock CLK_ISP_DIV_ISP1>, | |
| 219 | + <&isp_clock CLK_ISP_DIV_MCUISP0>, | |
| 220 | + <&isp_clock CLK_ISP_DIV_MCUISP1>, | |
| 221 | + <&clock CLK_MOUT_MPLL_USER_T>, | |
| 222 | + <&clock CLK_ACLK200>, | |
| 223 | + <&clock CLK_ACLK400_MCUISP>, | |
| 224 | + <&clock CLK_DIV_ACLK200>, | |
| 225 | + <&clock CLK_DIV_ACLK400_MCUISP>, | |
| 226 | + <&clock CLK_UART_ISP_SCLK>; | |
| 227 | + clock-names = "lite0", "lite1", "ppmuispx", | |
| 228 | + "ppmuispmx", "isp", | |
| 229 | + "drc", "fd", "mcuisp", | |
| 230 | + "gicisp", "mcuctl_isp", "pwm_isp", | |
| 231 | + "ispdiv0", "ispdiv1", "mcuispdiv0", | |
| 232 | + "mcuispdiv1", "mpll", "aclk200", | |
| 233 | + "aclk400mcuisp", "div_aclk200", | |
| 234 | + "div_aclk400mcuisp", "uart"; | |
| 235 | + iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>, | |
| 236 | + <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>; | |
| 237 | + iommu-names = "isp", "drc", "fd", "mcuctl"; | |
| 238 | + power-domains = <&pd_isp>; | |
| 239 | + | |
| 240 | + #address-cells = <1>; | |
| 241 | + #size-cells = <1>; | |
| 242 | + ranges; | |
| 243 | + | |
| 244 | + pmu@10020000 { | |
| 245 | + reg = <0x10020000 0x3000>; | |
| 246 | + }; | |
| 247 | + | |
| 248 | + i2c-isp@12140000 { | |
| 249 | + compatible = "samsung,exynos4212-i2c-isp"; | |
| 250 | + reg = <0x12140000 0x100>; | |
| 251 | + clocks = <&isp_clock CLK_ISP_I2C1_ISP>; | |
| 252 | + clock-names = "i2c_isp"; | |
| 253 | + pinctrl-0 = <&fimc_is_i2c1>; | |
| 254 | + pinctrl-names = "default"; | |
| 255 | + #address-cells = <1>; | |
| 256 | + #size-cells = <0>; | |
| 257 | + | |
| 258 | + image-sensor@10 { | |
| 259 | + compatible = "samsung,s5k6a3"; | |
| 260 | + reg = <0x10>; | |
| 261 | + svdda-supply = <&cam_io_reg>; | |
| 262 | + svddio-supply = <&ldo19_reg>; | |
| 263 | + afvdd-supply = <&ldo19_reg>; | |
| 264 | + clock-frequency = <24000000>; | |
| 265 | + /* CAM_B_CLKOUT */ | |
| 266 | + clocks = <&camera 1>; | |
| 267 | + clock-names = "extclk"; | |
| 268 | + gpios = <&gpm1 6 GPIO_ACTIVE_LOW>; | |
| 269 | + | |
| 270 | + port { | |
| 271 | + endpoint { | |
| 272 | + remote-endpoint = <&csis1_ep>; | |
| 273 | + data-lanes = <1>; | |
| 274 | + }; | |
| 275 | + }; | |
| 276 | + }; | |
| 277 | + }; | |
| 278 | + }; | |
| 279 | + }; | |
| @@ -0,0 +1,165 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/samsung,s5c73m3.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Samsung S5C73M3 8Mp camera ISP | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> | |
| 11 | + - Sylwester Nawrocki <s.nawrocki@samsung.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + The S5C73M3 camera ISP supports MIPI CSI-2 and parallel (ITU-R BT.656) | |
| 15 | + video data busses. The I2C bus is the main control bus and additionally the | |
| 16 | + SPI bus is used, mostly for transferring the firmware to and from the | |
| 17 | + device. Two slave device nodes corresponding to these control bus | |
| 18 | + interfaces are required and should be placed under respective bus | |
| 19 | + controller nodes. | |
| 20 | + | |
| 21 | +properties: | |
| 22 | + compatible: | |
| 23 | + const: samsung,s5c73m3 | |
| 24 | + | |
| 25 | + reg: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | + clocks: | |
| 29 | + maxItems: 1 | |
| 30 | + | |
| 31 | + clock-names: | |
| 32 | + items: | |
| 33 | + - const: cis_extclk | |
| 34 | + | |
| 35 | + clock-frequency: | |
| 36 | + default: 24000000 | |
| 37 | + description: cis_extclk clock frequency. | |
| 38 | + | |
| 39 | + standby-gpios: | |
| 40 | + maxItems: 1 | |
| 41 | + description: STANDBY pin. | |
| 42 | + | |
| 43 | + vdda-supply: | |
| 44 | + description: Analog power supply (1.2V). | |
| 45 | + | |
| 46 | + vdd-af-supply: | |
| 47 | + description: lens power supply (2.8V). | |
| 48 | + | |
| 49 | + vddio-cis-supply: | |
| 50 | + description: CIS I/O power supply (1.2V to 1.8V). | |
| 51 | + | |
| 52 | + vddio-host-supply: | |
| 53 | + description: Host I/O power supply (1.8V to 2.8V). | |
| 54 | + | |
| 55 | + vdd-int-supply: | |
| 56 | + description: Digital power supply (1.2V). | |
| 57 | + | |
| 58 | + vdd-reg-supply: | |
| 59 | + description: Regulator input power supply (2.8V). | |
| 60 | + | |
| 61 | + xshutdown-gpios: | |
| 62 | + maxItems: 1 | |
| 63 | + description: XSHUTDOWN pin. | |
| 64 | + | |
| 65 | + port: | |
| 66 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 67 | + additionalProperties: false | |
| 68 | + | |
| 69 | + properties: | |
| 70 | + endpoint: | |
| 71 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 72 | + unevaluatedProperties: false | |
| 73 | + | |
| 74 | + properties: | |
| 75 | + data-lanes: | |
| 76 | + items: | |
| 77 | + - const: 1 | |
| 78 | + - const: 2 | |
| 79 | + - const: 3 | |
| 80 | + - const: 4 | |
| 81 | + | |
| 82 | +required: | |
| 83 | + - compatible | |
| 84 | + - reg | |
| 85 | + | |
| 86 | +allOf: | |
| 87 | + - $ref: /schemas/spi/spi-peripheral-props.yaml# | |
| 88 | + - if: | |
| 89 | + required: | |
| 90 | + - spi-max-frequency | |
| 91 | + then: | |
| 92 | + properties: | |
| 93 | + # The SPI node is simplified firmware-transfer interface only | |
| 94 | + clocks: false | |
| 95 | + clock-names: false | |
| 96 | + standby-gpios: false | |
| 97 | + vdda-supply: false | |
| 98 | + vdd-af-supply: false | |
| 99 | + vddio-cis-supply: false | |
| 100 | + vddio-host-supply: false | |
| 101 | + vdd-int-supply: false | |
| 102 | + vdd-reg-supply: false | |
| 103 | + xshutdown-gpios: false | |
| 104 | + port: false | |
| 105 | + else: | |
| 106 | + required: | |
| 107 | + - clocks | |
| 108 | + - clock-names | |
| 109 | + - standby-gpios | |
| 110 | + - vdda-supply | |
| 111 | + - vdd-af-supply | |
| 112 | + - vddio-cis-supply | |
| 113 | + - vddio-host-supply | |
| 114 | + - vdd-int-supply | |
| 115 | + - vdd-reg-supply | |
| 116 | + - xshutdown-gpios | |
| 117 | + - port | |
| 118 | + | |
| 119 | +unevaluatedProperties: false | |
| 120 | + | |
| 121 | +examples: | |
| 122 | + - | | |
| 123 | + #include <dt-bindings/gpio/gpio.h> | |
| 124 | + | |
| 125 | + i2c { | |
| 126 | + #address-cells = <1>; | |
| 127 | + #size-cells = <0>; | |
| 128 | + | |
| 129 | + image-sensor@3c { | |
| 130 | + compatible = "samsung,s5c73m3"; | |
| 131 | + reg = <0x3c>; | |
| 132 | + clock-frequency = <24000000>; | |
| 133 | + clocks = <&camera 0>; | |
| 134 | + clock-names = "cis_extclk"; | |
| 135 | + standby-gpios = <&gpm0 6 GPIO_ACTIVE_LOW>; | |
| 136 | + vdda-supply = <&cam_vdda_reg>; | |
| 137 | + vdd-af-supply = <&cam_af_reg>; | |
| 138 | + vddio-cis-supply = <&ldo9_reg>; | |
| 139 | + vddio-host-supply = <&ldo18_reg>; | |
| 140 | + vdd-int-supply = <&buck9_reg>; | |
| 141 | + vdd-reg-supply = <&cam_io_reg>; | |
| 142 | + xshutdown-gpios = <&gpf1 3 GPIO_ACTIVE_LOW>; /* ISP_RESET */ | |
| 143 | + | |
| 144 | + port { | |
| 145 | + s5c73m3_ep: endpoint { | |
| 146 | + remote-endpoint = <&csis0_ep>; | |
| 147 | + data-lanes = <1 2 3 4>; | |
| 148 | + }; | |
| 149 | + }; | |
| 150 | + }; | |
| 151 | + }; | |
| 152 | + | |
| 153 | + spi { | |
| 154 | + #address-cells = <1>; | |
| 155 | + #size-cells = <0>; | |
| 156 | + | |
| 157 | + image-sensor@0 { | |
| 158 | + compatible = "samsung,s5c73m3"; | |
| 159 | + reg = <0>; | |
| 160 | + spi-max-frequency = <50000000>; | |
| 161 | + controller-data { | |
| 162 | + samsung,spi-feedback-delay = <2>; | |
| 163 | + }; | |
| 164 | + }; | |
| 165 | + }; | |
| @@ -1,209 +0,0 @@ | ||
| 1 | −Samsung S5P/Exynos SoC Camera Subsystem (FIMC) | |
| 2 | −---------------------------------------------- | |
| 3 | − | |
| 4 | −The S5P/Exynos SoC Camera subsystem comprises of multiple sub-devices | |
| 5 | −represented by separate device tree nodes. Currently this includes: FIMC (in | |
| 6 | −the S5P SoCs series known as CAMIF), MIPI CSIS, FIMC-LITE and FIMC-IS (ISP). | |
| 7 | − | |
| 8 | −The sub-subdevices are defined as child nodes of the common 'camera' node which | |
| 9 | −also includes common properties of the whole subsystem not really specific to | |
| 10 | −any single sub-device, like common camera port pins or the CAMCLK clock outputs | |
| 11 | −for external image sensors attached to an SoC. | |
| 12 | − | |
| 13 | −Common 'camera' node | |
| 14 | −-------------------- | |
| 15 | − | |
| 16 | −Required properties: | |
| 17 | − | |
| 18 | −- compatible: must be "samsung,fimc", "simple-bus" | |
| 19 | −- clocks: list of clock specifiers, corresponding to entries in | |
| 20 | − the clock-names property; | |
| 21 | −- clock-names : must contain "sclk_cam0", "sclk_cam1", "pxl_async0", | |
| 22 | − "pxl_async1" entries, matching entries in the clocks property. | |
| 23 | − | |
| 24 | −- #clock-cells: from the common clock bindings (../clock/clock-bindings.txt), | |
| 25 | − must be 1. A clock provider is associated with the 'camera' node and it should | |
| 26 | − be referenced by external sensors that use clocks provided by the SoC on | |
| 27 | − CAM_*_CLKOUT pins. The clock specifier cell stores an index of a clock. | |
| 28 | − The indices are 0, 1 for CAM_A_CLKOUT, CAM_B_CLKOUT clocks respectively. | |
| 29 | − | |
| 30 | −- clock-output-names: from the common clock bindings, should contain names of | |
| 31 | − clocks registered by the camera subsystem corresponding to CAM_A_CLKOUT, | |
| 32 | − CAM_B_CLKOUT output clocks respectively. | |
| 33 | − | |
| 34 | −The pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt must be used | |
| 35 | −to define a required pinctrl state named "default" and optional pinctrl states: | |
| 36 | −"idle", "active-a", active-b". These optional states can be used to switch the | |
| 37 | −camera port pinmux at runtime. The "idle" state should configure both the camera | |
| 38 | −ports A and B into high impedance state, especially the CAMCLK clock output | |
| 39 | −should be inactive. For the "active-a" state the camera port A must be activated | |
| 40 | −and the port B deactivated and for the state "active-b" it should be the other | |
| 41 | −way around. | |
| 42 | − | |
| 43 | −The 'camera' node must include at least one 'fimc' child node. | |
| 44 | − | |
| 45 | − | |
| 46 | −'fimc' device nodes | |
| 47 | −------------------- | |
| 48 | − | |
| 49 | −Required properties: | |
| 50 | − | |
| 51 | −- compatible: "samsung,s5pv210-fimc" for S5PV210, "samsung,exynos4210-fimc" | |
| 52 | − for Exynos4210 and "samsung,exynos4212-fimc" for Exynos4x12 SoCs; | |
| 53 | −- reg: physical base address and length of the registers set for the device; | |
| 54 | −- interrupts: should contain FIMC interrupt; | |
| 55 | −- clocks: list of clock specifiers, must contain an entry for each required | |
| 56 | − entry in clock-names; | |
| 57 | −- clock-names: must contain "fimc", "sclk_fimc" entries. | |
| 58 | −- samsung,pix-limits: an array of maximum supported image sizes in pixels, for | |
| 59 | − details refer to Table 2-1 in the S5PV210 SoC User Manual; The meaning of | |
| 60 | − each cell is as follows: | |
| 61 | − 0 - scaler input horizontal size, | |
| 62 | − 1 - input horizontal size for the scaler bypassed, | |
| 63 | − 2 - REAL_WIDTH without input rotation, | |
| 64 | − 3 - REAL_HEIGHT with input rotation, | |
| 65 | −- samsung,sysreg: a phandle to the SYSREG node. | |
| 66 | − | |
| 67 | −Each FIMC device should have an alias in the aliases node, in the form of | |
| 68 | −fimc<n>, where <n> is an integer specifying the IP block instance. | |
| 69 | − | |
| 70 | −Optional properties: | |
| 71 | − | |
| 72 | −- clock-frequency: maximum FIMC local clock (LCLK) frequency; | |
| 73 | −- samsung,min-pix-sizes: an array specyfing minimum image size in pixels at | |
| 74 | − the FIMC input and output DMA, in the first and second cell respectively. | |
| 75 | − Default value when this property is not present is <16 16>; | |
| 76 | −- samsung,min-pix-alignment: minimum supported image height alignment (first | |
| 77 | − cell) and the horizontal image offset (second cell). The values are in pixels | |
| 78 | − and default to <2 1> when this property is not present; | |
| 79 | −- samsung,mainscaler-ext: a boolean property indicating whether the FIMC IP | |
| 80 | − supports extended image size and has CIEXTEN register; | |
| 81 | −- samsung,rotators: a bitmask specifying whether this IP has the input and | |
| 82 | − the output rotator. Bits 4 and 0 correspond to input and output rotator | |
| 83 | − respectively. If a rotator is present its corresponding bit should be set. | |
| 84 | − Default value when this property is not specified is 0x11. | |
| 85 | −- samsung,cam-if: a bolean property indicating whether the IP block includes | |
| 86 | − the camera input interface. | |
| 87 | −- samsung,isp-wb: this property must be present if the IP block has the ISP | |
| 88 | − writeback input. | |
| 89 | −- samsung,lcd-wb: this property must be present if the IP block has the LCD | |
| 90 | − writeback input. | |
| 91 | − | |
| 92 | − | |
| 93 | −'parallel-ports' node | |
| 94 | −--------------------- | |
| 95 | − | |
| 96 | −This node should contain child 'port' nodes specifying active parallel video | |
| 97 | −input ports. It includes camera A and camera B inputs. 'reg' property in the | |
| 98 | −port nodes specifies data input - 1, 2 indicates input A, B respectively. | |
| 99 | − | |
| 100 | −Optional properties | |
| 101 | − | |
| 102 | −- samsung,camclk-out (deprecated) : specifies clock output for remote sensor, | |
| 103 | − 0 - CAM_A_CLKOUT, 1 - CAM_B_CLKOUT; | |
| 104 | − | |
| 105 | −Image sensor nodes | |
| 106 | −------------------ | |
| 107 | − | |
| 108 | −The sensor device nodes should be added to their control bus controller (e.g. | |
| 109 | −I2C0) nodes and linked to a port node in the csis or the parallel-ports node, | |
| 110 | −using the common video interfaces bindings, defined in video-interfaces.txt. | |
| 111 | − | |
| 112 | −Example: | |
| 113 | − | |
| 114 | − aliases { | |
| 115 | − fimc0 = &fimc_0; | |
| 116 | − }; | |
| 117 | − | |
| 118 | − /* Parallel bus IF sensor */ | |
| 119 | − i2c_0: i2c@13860000 { | |
| 120 | − s5k6aa: sensor@3c { | |
| 121 | − compatible = "samsung,s5k6aafx"; | |
| 122 | − reg = <0x3c>; | |
| 123 | − vddio-supply = <...>; | |
| 124 | − | |
| 125 | − clock-frequency = <24000000>; | |
| 126 | − clocks = <&camera 1>; | |
| 127 | − clock-names = "mclk"; | |
| 128 | − | |
| 129 | − port { | |
| 130 | − s5k6aa_ep: endpoint { | |
| 131 | − remote-endpoint = <&fimc0_ep>; | |
| 132 | − bus-width = <8>; | |
| 133 | − hsync-active = <0>; | |
| 134 | − vsync-active = <1>; | |
| 135 | − pclk-sample = <1>; | |
| 136 | − }; | |
| 137 | − }; | |
| 138 | − }; | |
| 139 | − | |
| 140 | − /* MIPI CSI-2 bus IF sensor */ | |
| 141 | − s5c73m3: sensor@1a { | |
| 142 | − compatible = "samsung,s5c73m3"; | |
| 143 | − reg = <0x1a>; | |
| 144 | − vddio-supply = <...>; | |
| 145 | − | |
| 146 | − clock-frequency = <24000000>; | |
| 147 | − clocks = <&camera 0>; | |
| 148 | − clock-names = "mclk"; | |
| 149 | − | |
| 150 | − port { | |
| 151 | − s5c73m3_1: endpoint { | |
| 152 | − data-lanes = <1 2 3 4>; | |
| 153 | − remote-endpoint = <&csis0_ep>; | |
| 154 | − }; | |
| 155 | − }; | |
| 156 | − }; | |
| 157 | − }; | |
| 158 | − | |
| 159 | − camera { | |
| 160 | − compatible = "samsung,fimc", "simple-bus"; | |
| 161 | − clocks = <&clock 132>, <&clock 133>, <&clock 351>, | |
| 162 | − <&clock 352>; | |
| 163 | − clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", | |
| 164 | − "pxl_async1"; | |
| 165 | − #clock-cells = <1>; | |
| 166 | − clock-output-names = "cam_a_clkout", "cam_b_clkout"; | |
| 167 | − pinctrl-names = "default"; | |
| 168 | − pinctrl-0 = <&cam_port_a_clk_active>; | |
| 169 | − #address-cells = <1>; | |
| 170 | − #size-cells = <1>; | |
| 171 | − | |
| 172 | − /* parallel camera ports */ | |
| 173 | − parallel-ports { | |
| 174 | − /* camera A input */ | |
| 175 | − port@1 { | |
| 176 | − reg = <1>; | |
| 177 | − fimc0_ep: endpoint { | |
| 178 | − remote-endpoint = <&s5k6aa_ep>; | |
| 179 | − bus-width = <8>; | |
| 180 | − hsync-active = <0>; | |
| 181 | − vsync-active = <1>; | |
| 182 | − pclk-sample = <1>; | |
| 183 | − }; | |
| 184 | − }; | |
| 185 | − }; | |
| 186 | − | |
| 187 | − fimc_0: fimc@11800000 { | |
| 188 | − compatible = "samsung,exynos4210-fimc"; | |
| 189 | − reg = <0x11800000 0x1000>; | |
| 190 | − interrupts = <0 85 0>; | |
| 191 | − }; | |
| 192 | − | |
| 193 | − csis_0: csis@11880000 { | |
| 194 | − compatible = "samsung,exynos4210-csis"; | |
| 195 | − reg = <0x11880000 0x1000>; | |
| 196 | − interrupts = <0 78 0>; | |
| 197 | − /* camera C input */ | |
| 198 | − port@3 { | |
| 199 | − reg = <3>; | |
| 200 | − csis0_ep: endpoint { | |
| 201 | − remote-endpoint = <&s5c73m3_ep>; | |
| 202 | − data-lanes = <1 2 3 4>; | |
| 203 | − samsung,csis-hs-settle = <12>; | |
| 204 | − }; | |
| 205 | − }; | |
| 206 | − }; | |
| 207 | − }; | |
| 208 | − | |
| 209 | −The MIPI-CSIS device binding is defined in samsung-mipi-csis.txt. | |
| @@ -1,81 +0,0 @@ | ||
| 1 | −Samsung S5P/Exynos SoC series MIPI CSI-2 receiver (MIPI CSIS) | |
| 2 | −------------------------------------------------------------- | |
| 3 | − | |
| 4 | −Required properties: | |
| 5 | − | |
| 6 | −- compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110), | |
| 7 | − "samsung,exynos4210-csis" for Exynos4210 (S5PC210), | |
| 8 | − "samsung,exynos4212-csis" for Exynos4212/Exynos4412, | |
| 9 | − "samsung,exynos5250-csis" for Exynos5250; | |
| 10 | −- reg : offset and length of the register set for the device; | |
| 11 | −- interrupts : should contain MIPI CSIS interrupt; the format of the | |
| 12 | − interrupt specifier depends on the interrupt controller; | |
| 13 | −- bus-width : maximum number of data lanes supported (SoC specific); | |
| 14 | −- vddio-supply : MIPI CSIS I/O and PLL voltage supply (e.g. 1.8V); | |
| 15 | −- vddcore-supply : MIPI CSIS Core voltage supply (e.g. 1.1V); | |
| 16 | −- clocks : list of clock specifiers, corresponding to entries in | |
| 17 | − clock-names property; | |
| 18 | −- clock-names : must contain "csis", "sclk_csis" entries, matching entries | |
| 19 | − in the clocks property. | |
| 20 | − | |
| 21 | −Optional properties: | |
| 22 | − | |
| 23 | −- clock-frequency : The IP's main (system bus) clock frequency in Hz, default | |
| 24 | − value when this property is not specified is 166 MHz; | |
| 25 | −- samsung,csis-wclk : CSI-2 wrapper clock selection. If this property is present | |
| 26 | − external clock from CMU will be used, or the bus clock if | |
| 27 | − if it's not specified. | |
| 28 | − | |
| 29 | −The device node should contain one 'port' child node with one child 'endpoint' | |
| 30 | −node, according to the bindings defined in Documentation/devicetree/bindings/ | |
| 31 | −media/video-interfaces.txt. The following are properties specific to those nodes. | |
| 32 | − | |
| 33 | −port node | |
| 34 | −--------- | |
| 35 | − | |
| 36 | −- reg : (required) must be 3 for camera C input (CSIS0) or 4 for | |
| 37 | − camera D input (CSIS1); | |
| 38 | − | |
| 39 | −endpoint node | |
| 40 | −------------- | |
| 41 | − | |
| 42 | −- data-lanes : (required) an array specifying active physical MIPI-CSI2 | |
| 43 | − data input lanes and their mapping to logical lanes; the | |
| 44 | − array's content is unused, only its length is meaningful; | |
| 45 | − | |
| 46 | −- samsung,csis-hs-settle : (optional) differential receiver (HS-RX) settle time; | |
| 47 | − | |
| 48 | − | |
| 49 | −Example: | |
| 50 | − | |
| 51 | − reg0: regulator@0 { | |
| 52 | − }; | |
| 53 | − | |
| 54 | − reg1: regulator@1 { | |
| 55 | − }; | |
| 56 | − | |
| 57 | −/* SoC properties */ | |
| 58 | − | |
| 59 | − csis_0: csis@11880000 { | |
| 60 | − compatible = "samsung,exynos4210-csis"; | |
| 61 | − reg = <0x11880000 0x1000>; | |
| 62 | − interrupts = <0 78 0>; | |
| 63 | − #address-cells = <1>; | |
| 64 | − #size-cells = <0>; | |
| 65 | − }; | |
| 66 | − | |
| 67 | −/* Board properties */ | |
| 68 | − | |
| 69 | − csis_0: csis@11880000 { | |
| 70 | − clock-frequency = <166000000>; | |
| 71 | − vddio-supply = <®0>; | |
| 72 | − vddcore-supply = <®1>; | |
| 73 | − port { | |
| 74 | − reg = <3>; /* 3 - CSIS0, 4 - CSIS1 */ | |
| 75 | − csis0_ep: endpoint { | |
| 76 | − remote-endpoint = <...>; | |
| 77 | − data-lanes = <1>, <2>; | |
| 78 | − samsung,csis-hs-settle = <12>; | |
| 79 | − }; | |
| 80 | − }; | |
| 81 | − }; | |
| @@ -1,97 +0,0 @@ | ||
| 1 | −Samsung S5C73M3 8Mp camera ISP | |
| 2 | −------------------------------ | |
| 3 | − | |
| 4 | −The S5C73M3 camera ISP supports MIPI CSI-2 and parallel (ITU-R BT.656) video | |
| 5 | −data busses. The I2C bus is the main control bus and additionally the SPI bus | |
| 6 | −is used, mostly for transferring the firmware to and from the device. Two | |
| 7 | −slave device nodes corresponding to these control bus interfaces are required | |
| 8 | −and should be placed under respective bus controller nodes. | |
| 9 | − | |
| 10 | −I2C slave device node | |
| 11 | −--------------------- | |
| 12 | − | |
| 13 | −Required properties: | |
| 14 | − | |
| 15 | −- compatible : "samsung,s5c73m3"; | |
| 16 | −- reg : I2C slave address of the sensor; | |
| 17 | −- vdd-int-supply : digital power supply (1.2V); | |
| 18 | −- vdda-supply : analog power supply (1.2V); | |
| 19 | −- vdd-reg-supply : regulator input power supply (2.8V); | |
| 20 | −- vddio-host-supply : host I/O power supply (1.8V to 2.8V); | |
| 21 | −- vddio-cis-supply : CIS I/O power supply (1.2V to 1.8V); | |
| 22 | −- vdd-af-supply : lens power supply (2.8V); | |
| 23 | −- xshutdown-gpios : specifier of GPIO connected to the XSHUTDOWN pin; | |
| 24 | −- standby-gpios : specifier of GPIO connected to the STANDBY pin; | |
| 25 | −- clocks : should contain list of phandle and clock specifier pairs | |
| 26 | − according to common clock bindings for the clocks described | |
| 27 | − in the clock-names property; | |
| 28 | −- clock-names : should contain "cis_extclk" entry for the CIS_EXTCLK clock; | |
| 29 | − | |
| 30 | −Optional properties: | |
| 31 | − | |
| 32 | −- clock-frequency : the frequency at which the "cis_extclk" clock should be | |
| 33 | − configured to operate, in Hz; if this property is not | |
| 34 | − specified default 24 MHz value will be used. | |
| 35 | − | |
| 36 | −The common video interfaces bindings (see video-interfaces.txt) should be used | |
| 37 | −to specify link from the S5C73M3 to an external image data receiver. The S5C73M3 | |
| 38 | −device node should contain one 'port' child node with an 'endpoint' subnode for | |
| 39 | −this purpose. The data link from a raw image sensor to the S5C73M3 can be | |
| 40 | −similarly specified, but it is optional since the S5C73M3 ISP and a raw image | |
| 41 | −sensor are usually inseparable and form a hybrid module. | |
| 42 | − | |
| 43 | −Following properties are valid for the endpoint node(s): | |
| 44 | − | |
| 45 | −endpoint subnode | |
| 46 | −---------------- | |
| 47 | − | |
| 48 | −- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in | |
| 49 | − video-interfaces.txt. This sensor doesn't support data lane remapping | |
| 50 | − and physical lane indexes in subsequent elements of the array should | |
| 51 | − be only consecutive ascending values. | |
| 52 | − | |
| 53 | −SPI device node | |
| 54 | −--------------- | |
| 55 | − | |
| 56 | −Required properties: | |
| 57 | − | |
| 58 | −- compatible : "samsung,s5c73m3"; | |
| 59 | − | |
| 60 | −For more details see description of the SPI busses bindings | |
| 61 | −(../spi/spi-bus.txt) and bindings of a specific bus controller. | |
| 62 | − | |
| 63 | −Example: | |
| 64 | − | |
| 65 | −i2c@138a000000 { | |
| 66 | − ... | |
| 67 | − s5c73m3@3c { | |
| 68 | − compatible = "samsung,s5c73m3"; | |
| 69 | − reg = <0x3c>; | |
| 70 | − vdd-int-supply = <&buck9_reg>; | |
| 71 | − vdda-supply = <&ldo17_reg>; | |
| 72 | − vdd-reg-supply = <&cam_io_reg>; | |
| 73 | − vddio-host-supply = <&ldo18_reg>; | |
| 74 | − vddio-cis-supply = <&ldo9_reg>; | |
| 75 | − vdd-af-supply = <&cam_af_reg>; | |
| 76 | − clock-frequency = <24000000>; | |
| 77 | − clocks = <&clk 0>; | |
| 78 | − clock-names = "cis_extclk"; | |
| 79 | − xshutdown-gpios = <&gpf1 3 1>; | |
| 80 | − standby-gpios = <&gpm0 1 1>; | |
| 81 | − port { | |
| 82 | − s5c73m3_ep: endpoint { | |
| 83 | − remote-endpoint = <&csis0_ep>; | |
| 84 | − data-lanes = <1 2 3 4>; | |
| 85 | − }; | |
| 86 | − }; | |
| 87 | − }; | |
| 88 | −}; | |
| 89 | − | |
| 90 | −spi@1392000 { | |
| 91 | − ... | |
| 92 | − s5c73m3_spi: s5c73m3@0 { | |
| 93 | − compatible = "samsung,s5c73m3"; | |
| 94 | − reg = <0>; | |
| 95 | − ... | |
| 96 | − }; | |
| 97 | −}; | |
| @@ -1,58 +0,0 @@ | ||
| 1 | −Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor with embedded SoC ISP | |
| 2 | −-------------------------------------------------------------------- | |
| 3 | − | |
| 4 | −Required properties: | |
| 5 | − | |
| 6 | −- compatible : "samsung,s5k5baf"; | |
| 7 | −- reg : I2C slave address of the sensor; | |
| 8 | −- vdda-supply : analog power supply 2.8V (2.6V to 3.0V); | |
| 9 | −- vddreg-supply : regulator input power supply 1.8V (1.7V to 1.9V) | |
| 10 | − or 2.8V (2.6V to 3.0); | |
| 11 | −- vddio-supply : I/O power supply 1.8V (1.65V to 1.95V) | |
| 12 | − or 2.8V (2.5V to 3.1V); | |
| 13 | −- stbyn-gpios : GPIO connected to STDBYN pin; | |
| 14 | −- rstn-gpios : GPIO connected to RSTN pin; | |
| 15 | −- clocks : list of phandle and clock specifier pairs | |
| 16 | − according to common clock bindings for the | |
| 17 | − clocks described in clock-names; | |
| 18 | −- clock-names : should include "mclk" for the sensor's master clock; | |
| 19 | − | |
| 20 | −Optional properties: | |
| 21 | − | |
| 22 | −- clock-frequency : the frequency at which the "mclk" clock should be | |
| 23 | − configured to operate, in Hz; if this property is not | |
| 24 | − specified default 24 MHz value will be used. | |
| 25 | − | |
| 26 | −The device node should contain one 'port' child node with one child 'endpoint' | |
| 27 | −node, according to the bindings defined in Documentation/devicetree/bindings/ | |
| 28 | −media/video-interfaces.txt. The following are properties specific to those | |
| 29 | −nodes. | |
| 30 | − | |
| 31 | −endpoint node | |
| 32 | −------------- | |
| 33 | − | |
| 34 | −- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in | |
| 35 | − video-interfaces.txt. If present it should be <1> - the device | |
| 36 | − supports only one data lane without re-mapping. | |
| 37 | − | |
| 38 | −Example: | |
| 39 | − | |
| 40 | −s5k5bafx@2d { | |
| 41 | − compatible = "samsung,s5k5baf"; | |
| 42 | − reg = <0x2d>; | |
| 43 | − vdda-supply = <&cam_io_en_reg>; | |
| 44 | − vddreg-supply = <&vt_core_15v_reg>; | |
| 45 | − vddio-supply = <&vtcam_reg>; | |
| 46 | − stbyn-gpios = <&gpl2 0 1>; | |
| 47 | − rstn-gpios = <&gpl2 1 1>; | |
| 48 | − clock-names = "mclk"; | |
| 49 | − clocks = <&clock_cam 0>; | |
| 50 | − clock-frequency = <24000000>; | |
| 51 | − | |
| 52 | − port { | |
| 53 | − s5k5bafx_ep: endpoint { | |
| 54 | − remote-endpoint = <&csis1_ep>; | |
| 55 | − data-lanes = <1>; | |
| 56 | − }; | |
| 57 | − }; | |
| 58 | −}; | |
| @@ -1,33 +0,0 @@ | ||
| 1 | −Samsung S5K6A3(YX) raw image sensor | |
| 2 | −--------------------------------- | |
| 3 | − | |
| 4 | −S5K6A3(YX) is a raw image sensor with MIPI CSI-2 and CCP2 image data interfaces | |
| 5 | −and CCI (I2C compatible) control bus. | |
| 6 | − | |
| 7 | −Required properties: | |
| 8 | − | |
| 9 | −- compatible : "samsung,s5k6a3"; | |
| 10 | −- reg : I2C slave address of the sensor; | |
| 11 | −- svdda-supply : core voltage supply; | |
| 12 | −- svddio-supply : I/O voltage supply; | |
| 13 | −- afvdd-supply : AF (actuator) voltage supply; | |
| 14 | −- gpios : specifier of a GPIO connected to the RESET pin; | |
| 15 | −- clocks : should contain list of phandle and clock specifier pairs | |
| 16 | − according to common clock bindings for the clocks described | |
| 17 | − in the clock-names property; | |
| 18 | −- clock-names : should contain "extclk" entry for the sensor's EXTCLK clock; | |
| 19 | − | |
| 20 | −Optional properties: | |
| 21 | − | |
| 22 | −- clock-frequency : the frequency at which the "extclk" clock should be | |
| 23 | − configured to operate, in Hz; if this property is not | |
| 24 | − specified default 24 MHz value will be used. | |
| 25 | − | |
| 26 | −The common video interfaces bindings (see video-interfaces.txt) should be | |
| 27 | −used to specify link to the image data receiver. The S5K6A3(YX) device | |
| 28 | −node should contain one 'port' child node with an 'endpoint' subnode. | |
| 29 | − | |
| 30 | −Following properties are valid for the endpoint node: | |
| 31 | − | |
| 32 | −- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in | |
| 33 | − video-interfaces.txt. The sensor supports only one data lane. | |
| @@ -1,26 +0,0 @@ | ||
| 1 | −* Silicon Labs FM Radio receiver | |
| 2 | − | |
| 3 | −The Silicon Labs Si470x is family of FM radio receivers with receive power scan | |
| 4 | −supporting 76-108 MHz, programmable through an I2C interface. | |
| 5 | −Some of them includes an RDS encoder. | |
| 6 | − | |
| 7 | −Required Properties: | |
| 8 | −- compatible: Should contain "silabs,si470x" | |
| 9 | −- reg: the I2C address of the device | |
| 10 | − | |
| 11 | −Optional Properties: | |
| 12 | −- interrupts : The interrupt number | |
| 13 | −- reset-gpios: GPIO specifier for the chips reset line | |
| 14 | − | |
| 15 | −Example: | |
| 16 | − | |
| 17 | −&i2c2 { | |
| 18 | − si470x@63 { | |
| 19 | − compatible = "silabs,si470x"; | |
| 20 | − reg = <0x63>; | |
| 21 | − | |
| 22 | − interrupt-parent = <&gpj2>; | |
| 23 | − interrupts = <4 IRQ_TYPE_EDGE_FALLING>; | |
| 24 | − reset-gpios = <&gpj2 5 GPIO_ACTIVE_HIGH>; | |
| 25 | − }; | |
| 26 | −}; | |
| @@ -0,0 +1,48 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/silabs,si470x.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Silicon Labs Si470x FM Radio Receiver | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Hans Verkuil <hverkuil@xs4all.nl> | |
| 11 | + - Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com> | |
| 12 | + | |
| 13 | +properties: | |
| 14 | + compatible: | |
| 15 | + const: silabs,si470x | |
| 16 | + | |
| 17 | + reg: | |
| 18 | + maxItems: 1 | |
| 19 | + | |
| 20 | + interrupts: | |
| 21 | + maxItems: 1 | |
| 22 | + | |
| 23 | + reset-gpios: | |
| 24 | + maxItems: 1 | |
| 25 | + | |
| 26 | +required: | |
| 27 | + - compatible | |
| 28 | + - reg | |
| 29 | + | |
| 30 | +additionalProperties: false | |
| 31 | + | |
| 32 | +examples: | |
| 33 | + - | | |
| 34 | + #include <dt-bindings/gpio/gpio.h> | |
| 35 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 36 | + | |
| 37 | + i2c { | |
| 38 | + #address-cells = <1>; | |
| 39 | + #size-cells = <0>; | |
| 40 | + | |
| 41 | + fmradio@10 { | |
| 42 | + compatible = "silabs,si470x"; | |
| 43 | + reg = <0x10>; | |
| 44 | + interrupt-parent = <&gpj2>; | |
| 45 | + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; | |
| 46 | + reset-gpios = <&gpj2 5 GPIO_ACTIVE_HIGH>; | |
| 47 | + }; | |
| 48 | + }; | |
| @@ -1,53 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | −%YAML 1.2 | |
| 3 | −--- | |
| 4 | −$id: http://devicetree.org/schemas/media/st,stm32-cec.yaml# | |
| 5 | −$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | − | |
| 7 | −title: STMicroelectronics STM32 CEC | |
| 8 | − | |
| 9 | −maintainers: | |
| 10 | − - Yannick Fertre <yannick.fertre@foss.st.com> | |
| 11 | − | |
| 12 | −properties: | |
| 13 | − compatible: | |
| 14 | − const: st,stm32-cec | |
| 15 | − | |
| 16 | − reg: | |
| 17 | − maxItems: 1 | |
| 18 | − | |
| 19 | − interrupts: | |
| 20 | − maxItems: 1 | |
| 21 | − | |
| 22 | − clocks: | |
| 23 | − items: | |
| 24 | − - description: Module Clock | |
| 25 | − - description: Bus Clock | |
| 26 | − | |
| 27 | − clock-names: | |
| 28 | − items: | |
| 29 | − - const: cec | |
| 30 | − - const: hdmi-cec | |
| 31 | − | |
| 32 | −required: | |
| 33 | − - compatible | |
| 34 | − - reg | |
| 35 | − - interrupts | |
| 36 | − - clocks | |
| 37 | − - clock-names | |
| 38 | − | |
| 39 | −additionalProperties: false | |
| 40 | − | |
| 41 | −examples: | |
| 42 | − - | | |
| 43 | − #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 44 | − #include <dt-bindings/clock/stm32mp1-clks.h> | |
| 45 | − cec: cec@40006c00 { | |
| 46 | − compatible = "st,stm32-cec"; | |
| 47 | − reg = <0x40006c00 0x400>; | |
| 48 | − interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; | |
| 49 | − clocks = <&rcc CEC_K>, <&clk_lse>; | |
| 50 | − clock-names = "cec", "hdmi-cec"; | |
| 51 | − }; | |
| 52 | − | |
| 53 | −... | |
| @@ -47,7 +47,7 @@ properties: · 46 unmodified lines | ||
| 47 | 47 | maxItems: 1 |
| 48 | 48 | |
| 49 | 49 | ti,camerrx-control: |
| 50 | − $ref: "/schemas/types.yaml#/definitions/phandle-array" | |
| 50 | + $ref: /schemas/types.yaml#/definitions/phandle-array | |
| 51 | 51 | items: |
| 52 | 52 | - items: |
| 53 | 53 | - description: phandle to device control module |
| @@ -56,6 +56,28 @@ analogue data is never read from the pixel matrix that are outside the · 55 unmodified lines | ||
| 56 | 56 | configured selection rectangle that designates crop. The difference has an |
| 57 | 57 | effect in device timing and likely also in power consumption. |
| 58 | 58 | |
| 59 | +CCS static data | |
| 60 | +--------------- | |
| 61 | + | |
| 62 | +The MIPI CCS driver supports CCS static data for all compliant devices, | |
| 63 | +including not just those compliant with CCS 1.1 but also CCS 1.0 and SMIA(++). | |
| 64 | +For CCS the file names are formed as | |
| 65 | + | |
| 66 | + ccs/ccs-sensor-vvvv-mmmm-rrrr.fw (sensor) and | |
| 67 | + ccs/ccs-module-vvvv-mmmm-rrrr.fw (module). | |
| 68 | + | |
| 69 | +For SMIA++ compliant devices the corresponding file names are | |
| 70 | + | |
| 71 | + ccs/smiapp-sensor-vv-mmmm-rr.fw (sensor) and | |
| 72 | + ccs/smiapp-module-vv-mmmm-rrrr.fw (module). | |
| 73 | + | |
| 74 | +For SMIA (non-++) compliant devices the static data file name is | |
| 75 | + | |
| 76 | + ccs/smia-sensor-vv-mmmm-rr.fw (sensor). | |
| 77 | + | |
| 78 | +vvvv or vv denotes MIPI and SMIA manufacturer IDs respectively, mmmm model ID | |
| 79 | +and rrrr or rr revision number. | |
| 80 | + | |
| 59 | 81 | Register definition generator |
| 60 | 82 | ----------------------------- |
| 61 | 83 | |
| @@ -67,6 +67,7 @@ ioctls must be supported by all video overlay devices. · 66 unmodified lines | ||
| 67 | 67 | Setup |
| 68 | 68 | ===== |
| 69 | 69 | |
| 70 | +*Note: support for this has been removed.* | |
| 70 | 71 | Before overlay can commence applications must program the driver with |
| 71 | 72 | frame buffer parameters, namely the address and size of the frame buffer |
| 72 | 73 | and the image format, for example RGB 5:6:5. The |
| @@ -92,11 +93,13 @@ A driver may support any (or none) of five clipping/blending methods: · 19 unmodified lines | ||
| 92 | 93 | 1. Chroma-keying displays the overlaid image only where pixels in the |
| 93 | 94 | primary graphics surface assume a certain color. |
| 94 | 95 | |
| 95 | −2. A bitmap can be specified where each bit corresponds to a pixel in | |
| 96 | +2. *Note: support for this has been removed.* | |
| 97 | + A bitmap can be specified where each bit corresponds to a pixel in | |
| 96 | 98 | the overlaid image. When the bit is set, the corresponding video |
| 97 | 99 | pixel is displayed, otherwise a pixel of the graphics surface. |
| 98 | 100 | |
| 99 | −3. A list of clipping rectangles can be specified. In these regions *no* | |
| 101 | +3. *Note: support for this has been removed.* | |
| 102 | + A list of clipping rectangles can be specified. In these regions *no* | |
| 100 | 103 | video is displayed, so the graphics surface can be seen here. |
| 101 | 104 | |
| 102 | 105 | 4. The framebuffer has an alpha channel that can be used to clip or |
| @@ -185,6 +188,7 @@ struct v4l2_window · 82 unmodified lines | ||
| 185 | 188 | be 0xRRGGBB on a little endian, 0xBBGGRR on a big endian host. |
| 186 | 189 | |
| 187 | 190 | ``struct v4l2_clip * clips`` |
| 191 | + *Note: support for this has been removed.* | |
| 188 | 192 | When chroma-keying has *not* been negotiated and |
| 189 | 193 | :ref:`VIDIOC_G_FBUF <VIDIOC_G_FBUF>` indicated this capability, |
| 190 | 194 | applications can set this field to point to an array of clipping |
| @@ -201,6 +205,7 @@ struct v4l2_window · 10 unmodified lines | ||
| 201 | 205 | are undefined. |
| 202 | 206 | |
| 203 | 207 | ``__u32 clipcount`` |
| 208 | + *Note: support for this has been removed.* | |
| 204 | 209 | When the application set the ``clips`` field, this field must |
| 205 | 210 | contain the number of clipping rectangles in the list. When clip |
| 206 | 211 | lists are not supported the driver ignores this field, its contents |
| @@ -208,6 +213,7 @@ struct v4l2_window · 1 unmodified line | ||
| 208 | 213 | supported but no clipping is desired this field must be set to zero. |
| 209 | 214 | |
| 210 | 215 | ``void * bitmap`` |
| 216 | + *Note: support for this has been removed.* | |
| 211 | 217 | When chroma-keying has *not* been negotiated and |
| 212 | 218 | :ref:`VIDIOC_G_FBUF <VIDIOC_G_FBUF>` indicated this capability, |
| 213 | 219 | applications can set this field to point to a clipping bit mask. |
| @@ -88,6 +88,11 @@ Compressed Formats · 87 unmodified lines | ||
| 88 | 88 | - ``V4L2_PIX_FMT_H263`` |
| 89 | 89 | - 'H263' |
| 90 | 90 | - H263 video elementary stream. |
| 91 | + * .. _V4L2-PIX-FMT-SPK: | |
| 92 | + | |
| 93 | + - ``V4L2_PIX_FMT_SPK`` | |
| 94 | + - 'SPK0' | |
| 95 | + - Sorenson Spark is an implementation of H.263 for use in Flash Video and Adobe Flash files | |
| 91 | 96 | * .. _V4L2-PIX-FMT-MPEG1: |
| 92 | 97 | |
| 93 | 98 | - ``V4L2_PIX_FMT_MPEG1`` |
| @@ -232,6 +237,26 @@ Compressed Formats · 138 unmodified lines | ||
| 232 | 237 | Metadata associated with the frame to decode is required to be passed |
| 233 | 238 | through the ``V4L2_CID_STATELESS_FWHT_PARAMS`` control. |
| 234 | 239 | See the :ref:`associated Codec Control ID <codec-stateless-fwht>`. |
| 240 | + * .. _V4L2-PIX-FMT-RV30: | |
| 241 | + | |
| 242 | + - ``V4L2_PIX_FMT_RV30`` | |
| 243 | + - 'RV30' | |
| 244 | + - RealVideo, or also spelled as Real Video, is a suite of | |
| 245 | + proprietary video compression formats developed by | |
| 246 | + RealNetworks - the specific format changes with the version. | |
| 247 | + RealVideo codecs are identified by four-character codes. | |
| 248 | + RV30 corresponds to RealVideo 8, suspected to be based | |
| 249 | + largely on an early draft of H.264 | |
| 250 | + * .. _V4L2-PIX-FMT-RV40: | |
| 251 | + | |
| 252 | + - ``V4L2_PIX_FMT_RV40`` | |
| 253 | + - 'RV40' | |
| 254 | + - RV40 represents RealVideo 9 and RealVideo 10. | |
| 255 | + RealVideo 9, suspected to be based on H.264. | |
| 256 | + RealVideo 10, aka RV9 EHQ, This refers to an improved encoder | |
| 257 | + for the RV9 format that is fully backwards compatible with | |
| 258 | + RV9 players - the format and decoder did not change, only | |
| 259 | + the encoder did. As a result, it uses the same FourCC. | |
| 235 | 260 | |
| 236 | 261 | .. raw:: latex |
| 237 | 262 | |
| @@ -257,6 +257,34 @@ the second byte and Y'\ :sub:`7-0` in the third byte. · 256 unmodified lines | ||
| 257 | 257 | - The padding bits contain undefined values that must be ignored by all |
| 258 | 258 | applications and drivers. |
| 259 | 259 | |
| 260 | +The next table lists the packed YUV 4:4:4 formats with 12 bits per component. | |
| 261 | +Expand the bits per component to 16 bits, data in the high bits, zeros in the low bits, | |
| 262 | +arranged in little endian order, storing 1 pixel in 6 bytes. | |
| 263 | + | |
| 264 | +.. flat-table:: Packed YUV 4:4:4 Image Formats (12bpc) | |
| 265 | + :header-rows: 1 | |
| 266 | + :stub-columns: 0 | |
| 267 | + | |
| 268 | + * - Identifier | |
| 269 | + - Code | |
| 270 | + - Byte 1-0 | |
| 271 | + - Byte 3-2 | |
| 272 | + - Byte 5-4 | |
| 273 | + - Byte 7-6 | |
| 274 | + - Byte 9-8 | |
| 275 | + - Byte 11-10 | |
| 276 | + | |
| 277 | + * .. _V4L2-PIX-FMT-YUV48-12: | |
| 278 | + | |
| 279 | + - ``V4L2_PIX_FMT_YUV48_12`` | |
| 280 | + - 'Y312' | |
| 281 | + | |
| 282 | + - Y'\ :sub:`0` | |
| 283 | + - Cb\ :sub:`0` | |
| 284 | + - Cr\ :sub:`0` | |
| 285 | + - Y'\ :sub:`1` | |
| 286 | + - Cb\ :sub:`1` | |
| 287 | + - Cr\ :sub:`1` | |
| 260 | 288 | |
| 261 | 289 | 4:2:2 Subsampling |
| 262 | 290 | ================= |
| @@ -953,6 +953,48 @@ number of bits for each component. · 952 unmodified lines | ||
| 953 | 953 | |
| 954 | 954 | \endgroup |
| 955 | 955 | |
| 956 | +12 Bits Per Component | |
| 957 | +============================== | |
| 958 | + | |
| 959 | +These formats store an RGB triplet in six or eight bytes, with 12 bits per component. | |
| 960 | +Expand the bits per component to 16 bits, data in the high bits, zeros in the low bits, | |
| 961 | +arranged in little endian order. | |
| 962 | + | |
| 963 | +.. raw:: latex | |
| 964 | + | |
| 965 | + \small | |
| 966 | + | |
| 967 | +.. flat-table:: RGB Formats With 12 Bits Per Component | |
| 968 | + :header-rows: 1 | |
| 969 | + | |
| 970 | + * - Identifier | |
| 971 | + - Code | |
| 972 | + - Byte 1-0 | |
| 973 | + - Byte 3-2 | |
| 974 | + - Byte 5-4 | |
| 975 | + - Byte 7-6 | |
| 976 | + * .. _V4L2-PIX-FMT-BGR48-12: | |
| 977 | + | |
| 978 | + - ``V4L2_PIX_FMT_BGR48_12`` | |
| 979 | + - 'B312' | |
| 980 | + | |
| 981 | + - B\ :sub:`15-4` | |
| 982 | + - G\ :sub:`15-4` | |
| 983 | + - R\ :sub:`15-4` | |
| 984 | + - | |
| 985 | + * .. _V4L2-PIX-FMT-ABGR64-12: | |
| 986 | + | |
| 987 | + - ``V4L2_PIX_FMT_ABGR64_12`` | |
| 988 | + - 'B412' | |
| 989 | + | |
| 990 | + - B\ :sub:`15-4` | |
| 991 | + - G\ :sub:`15-4` | |
| 992 | + - R\ :sub:`15-4` | |
| 993 | + - A\ :sub:`15-4` | |
| 994 | + | |
| 995 | +.. raw:: latex | |
| 996 | + | |
| 997 | + \normalsize | |
| 956 | 998 | |
| 957 | 999 | Deprecated RGB Formats |
| 958 | 1000 | ====================== |
| @@ -103,6 +103,17 @@ are often referred to as greyscale formats. · 102 unmodified lines | ||
| 103 | 103 | - ... |
| 104 | 104 | - ... |
| 105 | 105 | |
| 106 | + * .. _V4L2-PIX-FMT-Y012: | |
| 107 | + | |
| 108 | + - ``V4L2_PIX_FMT_Y012`` | |
| 109 | + - 'Y012' | |
| 110 | + | |
| 111 | + - Y'\ :sub:`0`\ [3:0] `0000` | |
| 112 | + - Y'\ :sub:`0`\ [11:4] | |
| 113 | + - ... | |
| 114 | + - ... | |
| 115 | + - ... | |
| 116 | + | |
| 106 | 117 | * .. _V4L2-PIX-FMT-Y14: |
| 107 | 118 | |
| 108 | 119 | - ``V4L2_PIX_FMT_Y14`` |
| @@ -146,3 +157,7 @@ are often referred to as greyscale formats. · 37 unmodified lines | ||
| 146 | 157 | than 16 bits. For example, 10 bits per pixel uses values in the range 0 to |
| 147 | 158 | 1023. For the IPU3_Y10 format 25 pixels are packed into 32 bytes, which |
| 148 | 159 | leaves the 6 most significant bits of the last byte padded with 0. |
| 160 | + | |
| 161 | + For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with | |
| 162 | + padding zeros in the 4 low bits, in contrast to the Y12 format, which has | |
| 163 | + its padding located in the most significant bits of the 16 bit word. | |
| @@ -123,6 +123,20 @@ All components are stored with the same number of bits per component. · 122 unmodified lines | ||
| 123 | 123 | - Cb, Cr |
| 124 | 124 | - Yes |
| 125 | 125 | - 4x4 tiles |
| 126 | + * - V4L2_PIX_FMT_P012 | |
| 127 | + - 'P012' | |
| 128 | + - 12 | |
| 129 | + - 4:2:0 | |
| 130 | + - Cb, Cr | |
| 131 | + - Yes | |
| 132 | + - Linear | |
| 133 | + * - V4L2_PIX_FMT_P012M | |
| 134 | + - 'PM12' | |
| 135 | + - 12 | |
| 136 | + - 4:2:0 | |
| 137 | + - Cb, Cr | |
| 138 | + - No | |
| 139 | + - Linear | |
| 126 | 140 | * - V4L2_PIX_FMT_NV16 |
| 127 | 141 | - 'NV16' |
| 128 | 142 | - 8 |
| @@ -586,6 +600,86 @@ Data in the 10 high bits, zeros in the 6 low bits, arranged in little endian ord · 457 unmodified lines | ||
| 586 | 600 | - Cb\ :sub:`11` |
| 587 | 601 | - Cr\ :sub:`11` |
| 588 | 602 | |
| 603 | +.. _V4L2-PIX-FMT-P012: | |
| 604 | +.. _V4L2-PIX-FMT-P012M: | |
| 605 | + | |
| 606 | +P012 and P012M | |
| 607 | +-------------- | |
| 608 | + | |
| 609 | +P012 is like NV12 with 12 bits per component, expanded to 16 bits. | |
| 610 | +Data in the 12 high bits, zeros in the 4 low bits, arranged in little endian order. | |
| 611 | + | |
| 612 | +.. flat-table:: Sample 4x4 P012 Image | |
| 613 | + :header-rows: 0 | |
| 614 | + :stub-columns: 0 | |
| 615 | + | |
| 616 | + * - start + 0: | |
| 617 | + - Y'\ :sub:`00` | |
| 618 | + - Y'\ :sub:`01` | |
| 619 | + - Y'\ :sub:`02` | |
| 620 | + - Y'\ :sub:`03` | |
| 621 | + * - start + 8: | |
| 622 | + - Y'\ :sub:`10` | |
| 623 | + - Y'\ :sub:`11` | |
| 624 | + - Y'\ :sub:`12` | |
| 625 | + - Y'\ :sub:`13` | |
| 626 | + * - start + 16: | |
| 627 | + - Y'\ :sub:`20` | |
| 628 | + - Y'\ :sub:`21` | |
| 629 | + - Y'\ :sub:`22` | |
| 630 | + - Y'\ :sub:`23` | |
| 631 | + * - start + 24: | |
| 632 | + - Y'\ :sub:`30` | |
| 633 | + - Y'\ :sub:`31` | |
| 634 | + - Y'\ :sub:`32` | |
| 635 | + - Y'\ :sub:`33` | |
| 636 | + * - start + 32: | |
| 637 | + - Cb\ :sub:`00` | |
| 638 | + - Cr\ :sub:`00` | |
| 639 | + - Cb\ :sub:`01` | |
| 640 | + - Cr\ :sub:`01` | |
| 641 | + * - start + 40: | |
| 642 | + - Cb\ :sub:`10` | |
| 643 | + - Cr\ :sub:`10` | |
| 644 | + - Cb\ :sub:`11` | |
| 645 | + - Cr\ :sub:`11` | |
| 646 | + | |
| 647 | +.. flat-table:: Sample 4x4 P012M Image | |
| 648 | + :header-rows: 0 | |
| 649 | + :stub-columns: 0 | |
| 650 | + | |
| 651 | + * - start0 + 0: | |
| 652 | + - Y'\ :sub:`00` | |
| 653 | + - Y'\ :sub:`01` | |
| 654 | + - Y'\ :sub:`02` | |
| 655 | + - Y'\ :sub:`03` | |
| 656 | + * - start0 + 8: | |
| 657 | + - Y'\ :sub:`10` | |
| 658 | + - Y'\ :sub:`11` | |
| 659 | + - Y'\ :sub:`12` | |
| 660 | + - Y'\ :sub:`13` | |
| 661 | + * - start0 + 16: | |
| 662 | + - Y'\ :sub:`20` | |
| 663 | + - Y'\ :sub:`21` | |
| 664 | + - Y'\ :sub:`22` | |
| 665 | + - Y'\ :sub:`23` | |
| 666 | + * - start0 + 24: | |
| 667 | + - Y'\ :sub:`30` | |
| 668 | + - Y'\ :sub:`31` | |
| 669 | + - Y'\ :sub:`32` | |
| 670 | + - Y'\ :sub:`33` | |
| 671 | + * - | |
| 672 | + * - start1 + 0: | |
| 673 | + - Cb\ :sub:`00` | |
| 674 | + - Cr\ :sub:`00` | |
| 675 | + - Cb\ :sub:`01` | |
| 676 | + - Cr\ :sub:`01` | |
| 677 | + * - start1 + 8: | |
| 678 | + - Cb\ :sub:`10` | |
| 679 | + - Cr\ :sub:`10` | |
| 680 | + - Cb\ :sub:`11` | |
| 681 | + - Cr\ :sub:`11` | |
| 682 | + | |
| 589 | 683 | |
| 590 | 684 | Fully Planar YUV Formats |
| 591 | 685 | ======================== |
| @@ -72,6 +72,7 @@ Function Reference · 71 unmodified lines | ||
| 72 | 72 | vidioc-subdev-g-frame-interval |
| 73 | 73 | vidioc-subdev-g-routing |
| 74 | 74 | vidioc-subdev-g-selection |
| 75 | + vidioc-subdev-g-client-cap | |
| 75 | 76 | vidioc-subdev-querycap |
| 76 | 77 | vidioc-subscribe-event |
| 77 | 78 | func-mmap |
| @@ -185,6 +185,16 @@ still cause this situation. · 184 unmodified lines | ||
| 185 | 185 | - ``p_u32`` |
| 186 | 186 | - A pointer to a matrix control of unsigned 32-bit values. Valid if |
| 187 | 187 | this control is of type ``V4L2_CTRL_TYPE_U32``. |
| 188 | + * - __u32 * | |
| 189 | + - ``p_s32`` | |
| 190 | + - A pointer to a matrix control of signed 32-bit values. Valid if | |
| 191 | + this control is of type ``V4L2_CTRL_TYPE_INTEGER`` and | |
| 192 | + ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is set. | |
| 193 | + * - __u32 * | |
| 194 | + - ``p_s64`` | |
| 195 | + - A pointer to a matrix control of signed 64-bit values. Valid if | |
| 196 | + this control is of type ``V4L2_CTRL_TYPE_INTEGER64`` and | |
| 197 | + ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is set. | |
| 188 | 198 | * - struct :c:type:`v4l2_area` * |
| 189 | 199 | - ``p_area`` |
| 190 | 200 | - A pointer to a struct :c:type:`v4l2_area`. Valid if this control is |
| @@ -49,6 +49,9 @@ of a graphics card. A non-destructive overlay blends video images into a · 48 unmodified lines | ||
| 49 | 49 | VGA signal or graphics into a video signal. *Video Output Overlays* are |
| 50 | 50 | always non-destructive. |
| 51 | 51 | |
| 52 | +Destructive overlay support has been removed: with modern GPUs and CPUs | |
| 53 | +this is no longer needed, and it was always a very dangerous feature. | |
| 54 | + | |
| 52 | 55 | To get the current parameters applications call the :ref:`VIDIOC_G_FBUF <VIDIOC_G_FBUF>` |
| 53 | 56 | ioctl with a pointer to a struct :c:type:`v4l2_framebuffer` |
| 54 | 57 | structure. The driver fills all fields of the structure or returns an |
| @@ -63,18 +66,12 @@ this structure, the driver prepares for the overlay and returns the · 8 unmodified lines | ||
| 63 | 66 | framebuffer parameters as :ref:`VIDIOC_G_FBUF <VIDIOC_G_FBUF>` does, or it returns an error |
| 64 | 67 | code. |
| 65 | 68 | |
| 66 | −To set the parameters for a *non-destructive Video Overlay*, | |
| 69 | +To set the parameters for a *Video Capture Overlay* | |
| 67 | 70 | applications must initialize the ``flags`` field, the ``fmt`` |
| 68 | 71 | substructure, and call :ref:`VIDIOC_S_FBUF <VIDIOC_G_FBUF>`. Again the driver prepares for |
| 69 | 72 | the overlay and returns the framebuffer parameters as :ref:`VIDIOC_G_FBUF <VIDIOC_G_FBUF>` |
| 70 | 73 | does, or it returns an error code. |
| 71 | 74 | |
| 72 | −For a *destructive Video Overlay* applications must additionally provide | |
| 73 | −a ``base`` address. Setting up a DMA to a random memory location can | |
| 74 | −jeopardize the system security, its stability or even damage the | |
| 75 | −hardware, therefore only the superuser can set the parameters for a | |
| 76 | −destructive video overlay. | |
| 77 | − | |
| 78 | 75 | .. tabularcolumns:: |p{3.5cm}|p{3.5cm}|p{3.5cm}|p{6.6cm}| |
| 79 | 76 | |
| 80 | 77 | .. c:type:: v4l2_framebuffer |
| @@ -100,17 +97,14 @@ destructive video overlay. · 19 unmodified lines | ||
| 100 | 97 | - ``base`` |
| 101 | 98 | - |
| 102 | 99 | - Physical base address of the framebuffer, that is the address of |
| 103 | − the pixel in the top left corner of the framebuffer. [#f1]_ | |
| 104 | − * - | |
| 105 | − - | |
| 106 | − - | |
| 107 | − - This field is irrelevant to *non-destructive Video Overlays*. For | |
| 108 | − *destructive Video Overlays* applications must provide a base | |
| 109 | − address. The driver may accept only base addresses which are a | |
| 110 | − multiple of two, four or eight bytes. For *Video Output Overlays* | |
| 111 | − the driver must return a valid base address, so applications can | |
| 100 | + the pixel in the top left corner of the framebuffer. | |
| 101 | + For :ref:`VIDIOC_S_FBUF <VIDIOC_G_FBUF>` this field is no longer supported | |
| 102 | + and the kernel will always set this to NULL. | |
| 103 | + For *Video Output Overlays* | |
| 104 | + the driver will return a valid base address, so applications can | |
| 112 | 105 | find the corresponding Linux framebuffer device (see |
| 113 | − :ref:`osd`). | |
| 106 | + :ref:`osd`). For *Video Capture Overlays* this field will always be | |
| 107 | + NULL. | |
| 114 | 108 | * - struct |
| 115 | 109 | - ``fmt`` |
| 116 | 110 | - |
| @@ -136,8 +130,7 @@ destructive video overlay. · 19 unmodified lines | ||
| 136 | 130 | * - |
| 137 | 131 | - |
| 138 | 132 | - |
| 139 | − - For *destructive Video Overlays* applications must initialize this | |
| 140 | − field. For *Video Output Overlays* the driver must return a valid | |
| 133 | + - For *Video Output Overlays* the driver must return a valid | |
| 141 | 134 | format. |
| 142 | 135 | * - |
| 143 | 136 | - |
| @@ -165,13 +158,6 @@ destructive video overlay. · 21 unmodified lines | ||
| 165 | 158 | |
| 166 | 159 | This field is irrelevant to *non-destructive Video Overlays*. |
| 167 | 160 | |
| 168 | − For *destructive Video Overlays* both applications and drivers can | |
| 169 | − set this field to request padding bytes at the end of each line. | |
| 170 | − Drivers however may ignore the requested value, returning | |
| 171 | − ``width`` times bytes-per-pixel or a larger value required by the | |
| 172 | − hardware. That implies applications can just set this field to | |
| 173 | − zero to get a reasonable default. | |
| 174 | − | |
| 175 | 161 | For *Video Output Overlays* the driver must return a valid value. |
| 176 | 162 | |
| 177 | 163 | Video hardware may access padding bytes, therefore they must |
| @@ -190,9 +176,8 @@ destructive video overlay. · 12 unmodified lines | ||
| 190 | 176 | * - |
| 191 | 177 | - __u32 |
| 192 | 178 | - ``sizeimage`` |
| 193 | − - This field is irrelevant to *non-destructive Video Overlays*. For | |
| 194 | − *destructive Video Overlays* applications must initialize this | |
| 195 | − field. For *Video Output Overlays* the driver must return a valid | |
| 179 | + - This field is irrelevant to *non-destructive Video Overlays*. | |
| 180 | + For *Video Output Overlays* the driver must return a valid | |
| 196 | 181 | format. |
| 197 | 182 | |
| 198 | 183 | Together with ``base`` it defines the framebuffer memory |
| @@ -232,9 +217,11 @@ destructive video overlay. · 33 unmodified lines | ||
| 232 | 217 | * - ``V4L2_FBUF_CAP_LIST_CLIPPING`` |
| 233 | 218 | - 0x0004 |
| 234 | 219 | - The device supports clipping using a list of clip rectangles. |
| 220 | + Note that this is no longer supported. | |
| 235 | 221 | * - ``V4L2_FBUF_CAP_BITMAP_CLIPPING`` |
| 236 | 222 | - 0x0008 |
| 237 | 223 | - The device supports clipping using a bit mask. |
| 224 | + Note that this is no longer supported. | |
| 238 | 225 | * - ``V4L2_FBUF_CAP_LOCAL_ALPHA`` |
| 239 | 226 | - 0x0010 |
| 240 | 227 | - The device supports clipping/blending using the alpha channel of |
| @@ -342,10 +329,3 @@ EPERM · 101 unmodified lines | ||
| 342 | 329 | |
| 343 | 330 | EINVAL |
| 344 | 331 | The :ref:`VIDIOC_S_FBUF <VIDIOC_G_FBUF>` parameters are unsuitable. |
| 345 | − | |
| 346 | −.. [#f1] | |
| 347 | − A physical base address may not suit all platforms. GK notes in | |
| 348 | − theory we should pass something like PCI device + memory region + | |
| 349 | − offset instead. If you encounter problems please discuss on the | |
| 350 | − linux-media mailing list: | |
| 351 | − `https://linuxtv.org/lists.php <https://linuxtv.org/lists.php>`__. | |
| @@ -31,18 +31,30 @@ Arguments · 30 unmodified lines | ||
| 31 | 31 | Description |
| 32 | 32 | =========== |
| 33 | 33 | |
| 34 | −This ioctl allows applications to enumerate all frame sizes supported by | |
| 35 | −a sub-device on the given pad for the given media bus format. Supported | |
| 36 | −formats can be retrieved with the | |
| 34 | +This ioctl allows applications to access the enumeration of frame sizes | |
| 35 | +supported by a sub-device on the specified pad | |
| 36 | +for the specified media bus format. | |
| 37 | +Supported formats can be retrieved with the | |
| 37 | 38 | :ref:`VIDIOC_SUBDEV_ENUM_MBUS_CODE` |
| 38 | 39 | ioctl. |
| 39 | 40 | |
| 40 | −To enumerate frame sizes applications initialize the ``pad``, ``which`` | |
| 41 | −, ``code`` and ``index`` fields of the struct | |
| 42 | −:c:type:`v4l2_subdev_mbus_code_enum` and | |
| 43 | −call the :ref:`VIDIOC_SUBDEV_ENUM_FRAME_SIZE` ioctl with a pointer to the | |
| 44 | −structure. Drivers fill the minimum and maximum frame sizes or return an | |
| 45 | −EINVAL error code if one of the input parameters is invalid. | |
| 41 | +The enumerations are defined by the driver, and indexed using the ``index`` field | |
| 42 | +of the struct :c:type:`v4l2_subdev_frame_size_enum`. | |
| 43 | +Each pair of ``pad`` and ``code`` correspond to a separate enumeration. | |
| 44 | +Each enumeration starts with the ``index`` of 0, and | |
| 45 | +the lowest invalid index marks the end of the enumeration. | |
| 46 | + | |
| 47 | +Therefore, to enumerate frame sizes allowed on the specified pad | |
| 48 | +and using the specified mbus format, initialize the | |
| 49 | +``pad``, ``which``, and ``code`` fields to desired values, | |
| 50 | +and set ``index`` to 0. | |
| 51 | +Then call the :ref:`VIDIOC_SUBDEV_ENUM_FRAME_SIZE` ioctl with a pointer to the | |
| 52 | +structure. | |
| 53 | + | |
| 54 | +A successful call will return with minimum and maximum frame sizes filled in. | |
| 55 | +Repeat with increasing ``index`` until ``EINVAL`` is received. | |
| 56 | +``EINVAL`` means that either no more entries are available in the enumeration, | |
| 57 | +or that an input parameter was invalid. | |
| 46 | 58 | |
| 47 | 59 | Sub-devices that only support discrete frame sizes (such as most |
| 48 | 60 | sensors) will return one or more frame sizes with identical minimum and |
| @@ -72,26 +84,28 @@ information about try formats. · 23 unmodified lines | ||
| 72 | 84 | |
| 73 | 85 | * - __u32 |
| 74 | 86 | - ``index`` |
| 75 | − - Number of the format in the enumeration, set by the application. | |
| 87 | + - Index of the frame size in the enumeration belonging to the given pad | |
| 88 | + and format. Filled in by the application. | |
| 76 | 89 | * - __u32 |
| 77 | 90 | - ``pad`` |
| 78 | 91 | - Pad number as reported by the media controller API. |
| 92 | + Filled in by the application. | |
| 79 | 93 | * - __u32 |
| 80 | 94 | - ``code`` |
| 81 | 95 | - The media bus format code, as defined in |
| 82 | − :ref:`v4l2-mbus-format`. | |
| 96 | + :ref:`v4l2-mbus-format`. Filled in by the application. | |
| 83 | 97 | * - __u32 |
| 84 | 98 | - ``min_width`` |
| 85 | − - Minimum frame width, in pixels. | |
| 99 | + - Minimum frame width, in pixels. Filled in by the driver. | |
| 86 | 100 | * - __u32 |
| 87 | 101 | - ``max_width`` |
| 88 | − - Maximum frame width, in pixels. | |
| 102 | + - Maximum frame width, in pixels. Filled in by the driver. | |
| 89 | 103 | * - __u32 |
| 90 | 104 | - ``min_height`` |
| 91 | − - Minimum frame height, in pixels. | |
| 105 | + - Minimum frame height, in pixels. Filled in by the driver. | |
| 92 | 106 | * - __u32 |
| 93 | 107 | - ``max_height`` |
| 94 | − - Maximum frame height, in pixels. | |
| 108 | + - Maximum frame height, in pixels. Filled in by the driver. | |
| 95 | 109 | * - __u32 |
| 96 | 110 | - ``which`` |
| 97 | 111 | - Frame sizes to be enumerated, from enum |
| @@ -31,15 +31,28 @@ Arguments · 30 unmodified lines | ||
| 31 | 31 | Description |
| 32 | 32 | =========== |
| 33 | 33 | |
| 34 | −To enumerate media bus formats available at a given sub-device pad | |
| 35 | −applications initialize the ``pad``, ``which`` and ``index`` fields of | |
| 36 | −struct | |
| 37 | −:c:type:`v4l2_subdev_mbus_code_enum` and | |
| 38 | −call the :ref:`VIDIOC_SUBDEV_ENUM_MBUS_CODE` ioctl with a pointer to this | |
| 39 | −structure. Drivers fill the rest of the structure or return an ``EINVAL`` | |
| 40 | −error code if either the ``pad`` or ``index`` are invalid. All media bus | |
| 41 | −formats are enumerable by beginning at index zero and incrementing by | |
| 42 | −one until ``EINVAL`` is returned. | |
| 34 | +This call is used by the application to access the enumeration | |
| 35 | +of media bus formats for the selected pad. | |
| 36 | + | |
| 37 | +The enumerations are defined by the driver, and indexed using the ``index`` field | |
| 38 | +of struct :c:type:`v4l2_subdev_mbus_code_enum`. | |
| 39 | +Each enumeration starts with the ``index`` of 0, and | |
| 40 | +the lowest invalid index marks the end of enumeration. | |
| 41 | + | |
| 42 | +Therefore, to enumerate media bus formats available at a given sub-device pad, | |
| 43 | +initialize the ``pad``, and ``which`` fields to desired values, | |
| 44 | +and set ``index`` to 0. | |
| 45 | +Then call the :ref:`VIDIOC_SUBDEV_ENUM_MBUS_CODE` ioctl | |
| 46 | +with a pointer to this structure. | |
| 47 | + | |
| 48 | +A successful call will return with the ``code`` field filled in | |
| 49 | +with a mbus code value. | |
| 50 | +Repeat with increasing ``index`` until ``EINVAL`` is received. | |
| 51 | +``EINVAL`` means that either ``pad`` is invalid, | |
| 52 | +or that there are no more codes available at this pad. | |
| 53 | + | |
| 54 | +The driver must not return the same value of ``code`` for different indices | |
| 55 | +at the same pad. | |
| 43 | 56 | |
| 44 | 57 | Available media bus formats may depend on the current 'try' formats at |
| 45 | 58 | other pads of the sub-device, as well as on the current active links. |
| @@ -57,14 +70,16 @@ information about the try formats. · 11 unmodified lines | ||
| 57 | 70 | |
| 58 | 71 | * - __u32 |
| 59 | 72 | - ``pad`` |
| 60 | − - Pad number as reported by the media controller API. | |
| 73 | + - Pad number as reported by the media controller API. Filled in by the | |
| 74 | + application. | |
| 61 | 75 | * - __u32 |
| 62 | 76 | - ``index`` |
| 63 | − - Number of the format in the enumeration, set by the application. | |
| 77 | + - Index of the mbus code in the enumeration belonging to the given pad. | |
| 78 | + Filled in by the application. | |
| 64 | 79 | * - __u32 |
| 65 | 80 | - ``code`` |
| 66 | 81 | - The media bus format code, as defined in |
| 67 | − :ref:`v4l2-mbus-format`. | |
| 82 | + :ref:`v4l2-mbus-format`. Filled in by the driver. | |
| 68 | 83 | * - __u32 |
| 69 | 84 | - ``which`` |
| 70 | 85 | - Media bus format codes to be enumerated, from enum |
| @@ -0,0 +1,83 @@ | ||
| 1 | +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later | |
| 2 | +.. c:namespace:: V4L | |
| 3 | + | |
| 4 | +.. _VIDIOC_SUBDEV_G_CLIENT_CAP: | |
| 5 | + | |
| 6 | +************************************************************ | |
| 7 | +ioctl VIDIOC_SUBDEV_G_CLIENT_CAP, VIDIOC_SUBDEV_S_CLIENT_CAP | |
| 8 | +************************************************************ | |
| 9 | + | |
| 10 | +Name | |
| 11 | +==== | |
| 12 | + | |
| 13 | +VIDIOC_SUBDEV_G_CLIENT_CAP - VIDIOC_SUBDEV_S_CLIENT_CAP - Get or set client | |
| 14 | +capabilities. | |
| 15 | + | |
| 16 | +Synopsis | |
| 17 | +======== | |
| 18 | + | |
| 19 | +.. c:macro:: VIDIOC_SUBDEV_G_CLIENT_CAP | |
| 20 | + | |
| 21 | +``int ioctl(int fd, VIDIOC_SUBDEV_G_CLIENT_CAP, struct v4l2_subdev_client_capability *argp)`` | |
| 22 | + | |
| 23 | +.. c:macro:: VIDIOC_SUBDEV_S_CLIENT_CAP | |
| 24 | + | |
| 25 | +``int ioctl(int fd, VIDIOC_SUBDEV_S_CLIENT_CAP, struct v4l2_subdev_client_capability *argp)`` | |
| 26 | + | |
| 27 | +Arguments | |
| 28 | +========= | |
| 29 | + | |
| 30 | +``fd`` | |
| 31 | + File descriptor returned by :ref:`open() <func-open>`. | |
| 32 | + | |
| 33 | +``argp`` | |
| 34 | + Pointer to struct :c:type:`v4l2_subdev_client_capability`. | |
| 35 | + | |
| 36 | +Description | |
| 37 | +=========== | |
| 38 | + | |
| 39 | +These ioctls are used to get and set the client (the application using the | |
| 40 | +subdevice ioctls) capabilities. The client capabilities are stored in the file | |
| 41 | +handle of the opened subdev device node, and the client must set the | |
| 42 | +capabilities for each opened subdev separately. | |
| 43 | + | |
| 44 | +By default no client capabilities are set when a subdev device node is opened. | |
| 45 | + | |
| 46 | +The purpose of the client capabilities are to inform the kernel of the behavior | |
| 47 | +of the client, mainly related to maintaining compatibility with different | |
| 48 | +kernel and userspace versions. | |
| 49 | + | |
| 50 | +The ``VIDIOC_SUBDEV_G_CLIENT_CAP`` ioctl returns the current client capabilities | |
| 51 | +associated with the file handle ``fd``. | |
| 52 | + | |
| 53 | +The ``VIDIOC_SUBDEV_S_CLIENT_CAP`` ioctl sets client capabilities for the file | |
| 54 | +handle ``fd``. The new capabilities fully replace the current capabilities, the | |
| 55 | +ioctl can therefore also be used to remove capabilities that have previously | |
| 56 | +been set. | |
| 57 | + | |
| 58 | +``VIDIOC_SUBDEV_S_CLIENT_CAP`` modifies the struct | |
| 59 | +:c:type:`v4l2_subdev_client_capability` to reflect the capabilities that have | |
| 60 | +been accepted. A common case for the kernel not accepting a capability is that | |
| 61 | +the kernel is older than the headers the userspace uses, and thus the capability | |
| 62 | +is unknown to the kernel. | |
| 63 | + | |
| 64 | +.. flat-table:: Client Capabilities | |
| 65 | + :header-rows: 1 | |
| 66 | + | |
| 67 | + * - Capability | |
| 68 | + - Description | |
| 69 | + * - ``V4L2_SUBDEV_CLIENT_CAP_STREAMS`` | |
| 70 | + - The client is aware of streams. Setting this flag enables the use | |
| 71 | + of 'stream' fields (referring to the stream number) with various | |
| 72 | + ioctls. If this is not set (which is the default), the 'stream' fields | |
| 73 | + will be forced to 0 by the kernel. | |
| 74 | + | |
| 75 | +Return Value | |
| 76 | +============ | |
| 77 | + | |
| 78 | +On success 0 is returned, on error -1 and the ``errno`` variable is set | |
| 79 | +appropriately. The generic error codes are described at the | |
| 80 | +:ref:`Generic Error Codes <gen-errors>` chapter. | |
| 81 | + | |
| 82 | +ENOIOCTLCMD | |
| 83 | + The kernel does not support this ioctl. | |
| @@ -1227,12 +1227,6 @@ F: Documentation/devicetree/bindings/iio/addac/adi,ad74413r.yaml · 1226 unmodified lines | ||
| 1227 | 1227 | F: drivers/iio/addac/ad74413r.c |
| 1228 | 1228 | F: include/dt-bindings/iio/addac/adi,ad74413r.h |
| 1229 | 1229 | |
| 1230 | −ANALOG DEVICES INC AD9389B DRIVER | |
| 1231 | −M: Hans Verkuil <hverkuil-cisco@xs4all.nl> | |
| 1232 | −L: linux-media@vger.kernel.org | |
| 1233 | −S: Maintained | |
| 1234 | −F: drivers/media/i2c/ad9389b* | |
| 1235 | − | |
| 1236 | 1230 | ANALOG DEVICES INC ADA4250 DRIVER |
| 1237 | 1231 | M: Antoniu Miclaus <antoniu.miclaus@analog.com> |
| 1238 | 1232 | L: linux-iio@vger.kernel.org |
| @@ -8441,14 +8435,6 @@ L: platform-driver-x86@vger.kernel.org · 7202 unmodified lines | ||
| 8441 | 8435 | S: Maintained |
| 8442 | 8436 | F: drivers/platform/x86/fujitsu-laptop.c |
| 8443 | 8437 | |
| 8444 | −FUJITSU M-5MO LS CAMERA ISP DRIVER | |
| 8445 | −M: Kyungmin Park <kyungmin.park@samsung.com> | |
| 8446 | −M: Heungjun Kim <riverful.kim@samsung.com> | |
| 8447 | −L: linux-media@vger.kernel.org | |
| 8448 | −S: Maintained | |
| 8449 | −F: drivers/media/i2c/m5mols/ | |
| 8450 | −F: include/media/i2c/m5mols.h | |
| 8451 | − | |
| 8452 | 8438 | FUJITSU TABLET EXTRAS |
| 8453 | 8439 | M: Robert Gerlach <khnz@gmx.de> |
| 8454 | 8440 | L: platform-driver-x86@vger.kernel.org |
| @@ -14206,14 +14192,6 @@ L: linux-mtd@lists.infradead.org · 5751 unmodified lines | ||
| 14206 | 14192 | S: Maintained |
| 14207 | 14193 | F: drivers/mtd/devices/docg3* |
| 14208 | 14194 | |
| 14209 | −MT9M032 APTINA SENSOR DRIVER | |
| 14210 | −M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
| 14211 | −L: linux-media@vger.kernel.org | |
| 14212 | −S: Maintained | |
| 14213 | −T: git git://linuxtv.org/media_tree.git | |
| 14214 | −F: drivers/media/i2c/mt9m032.c | |
| 14215 | −F: include/media/i2c/mt9m032.h | |
| 14216 | − | |
| 14217 | 14195 | MT9P031 APTINA CAMERA SENSOR |
| 14218 | 14196 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| 14219 | 14197 | L: linux-media@vger.kernel.org |
| @@ -14223,14 +14201,6 @@ F: Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml · 3 unmodified lines | ||
| 14223 | 14201 | F: drivers/media/i2c/mt9p031.c |
| 14224 | 14202 | F: include/media/i2c/mt9p031.h |
| 14225 | 14203 | |
| 14226 | −MT9T001 APTINA CAMERA SENSOR | |
| 14227 | −M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
| 14228 | −L: linux-media@vger.kernel.org | |
| 14229 | −S: Maintained | |
| 14230 | −T: git git://linuxtv.org/media_tree.git | |
| 14231 | −F: drivers/media/i2c/mt9t001.c | |
| 14232 | −F: include/media/i2c/mt9t001.h | |
| 14233 | − | |
| 14234 | 14204 | MT9T112 APTINA CAMERA SENSOR |
| 14235 | 14205 | M: Jacopo Mondi <jacopo@jmondi.org> |
| 14236 | 14206 | L: linux-media@vger.kernel.org |
| @@ -14983,6 +14953,13 @@ F: Documentation/devicetree/bindings/clock/imx* · 746 unmodified lines | ||
| 14983 | 14953 | F: drivers/clk/imx/ |
| 14984 | 14954 | F: include/dt-bindings/clock/imx* |
| 14985 | 14955 | |
| 14956 | +NXP i.MX 8M ISI DRIVER | |
| 14957 | +M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
| 14958 | +L: linux-media@vger.kernel.org | |
| 14959 | +S: Maintained | |
| 14960 | +F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml | |
| 14961 | +F: drivers/media/platform/nxp/imx8-isi/ | |
| 14962 | + | |
| 14986 | 14963 | NXP i.MX 8MQ DCSS DRIVER |
| 14987 | 14964 | M: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com> |
| 14988 | 14965 | R: Lucas Stach <l.stach@pengutronix.de> |
| @@ -15410,6 +15387,7 @@ M: Shunqian Zheng <zhengsq@rock-chips.com> · 421 unmodified lines | ||
| 15410 | 15387 | L: linux-media@vger.kernel.org |
| 15411 | 15388 | S: Maintained |
| 15412 | 15389 | T: git git://linuxtv.org/media_tree.git |
| 15390 | +F: Documentation/devicetree/bindings/media/i2c/ovti,ov2685.yaml | |
| 15413 | 15391 | F: drivers/media/i2c/ov2685.c |
| 15414 | 15392 | |
| 15415 | 15393 | OMNIVISION OV2740 SENSOR DRIVER |
| @@ -15501,7 +15479,7 @@ F: Documentation/devicetree/bindings/media/i2c/ov7740.txt · 85 unmodified lines | ||
| 15501 | 15479 | F: drivers/media/i2c/ov7740.c |
| 15502 | 15480 | |
| 15503 | 15481 | OMNIVISION OV8856 SENSOR DRIVER |
| 15504 | −M: Dongchun Zhu <dongchun.zhu@mediatek.com> | |
| 15482 | +M: Sakari Ailus <sakari.ailus@linux.intel.com> | |
| 15505 | 15483 | L: linux-media@vger.kernel.org |
| 15506 | 15484 | S: Maintained |
| 15507 | 15485 | T: git git://linuxtv.org/media_tree.git |
| @@ -17260,6 +17238,7 @@ F: drivers/net/wwan/qcom_bam_dmux.c · 1752 unmodified lines | ||
| 17260 | 17238 | QUALCOMM CAMERA SUBSYSTEM DRIVER |
| 17261 | 17239 | M: Robert Foss <rfoss@kernel.org> |
| 17262 | 17240 | M: Todor Tomov <todor.too@gmail.com> |
| 17241 | +M: Bryan O'Donoghue <bryan.odonoghue@linaro.org> | |
| 17263 | 17242 | L: linux-media@vger.kernel.org |
| 17264 | 17243 | S: Maintained |
| 17265 | 17244 | F: Documentation/admin-guide/media/qcom_camss.rst |
| @@ -18536,6 +18515,7 @@ M: Sylwester Nawrocki <s.nawrocki@samsung.com> · 1270 unmodified lines | ||
| 18536 | 18515 | M: Andrzej Hajda <andrzej.hajda@intel.com> |
| 18537 | 18516 | L: linux-media@vger.kernel.org |
| 18538 | 18517 | S: Supported |
| 18518 | +F: Documentation/devicetree/bindings/media/samsung,s5c73m3.yaml | |
| 18539 | 18519 | F: drivers/media/i2c/s5c73m3/* |
| 18540 | 18520 | |
| 18541 | 18521 | SAMSUNG S5K5BAF CAMERA DRIVER |
| @@ -18560,6 +18540,11 @@ M: Sylwester Nawrocki <s.nawrocki@samsung.com> · 18 unmodified lines | ||
| 18560 | 18540 | L: linux-media@vger.kernel.org |
| 18561 | 18541 | S: Supported |
| 18562 | 18542 | Q: https://patchwork.linuxtv.org/project/linux-media/list/ |
| 18543 | +F: Documentation/devicetree/bindings/media/samsung,exynos4210-csis.yaml | |
| 18544 | +F: Documentation/devicetree/bindings/media/samsung,exynos4210-fimc.yaml | |
| 18545 | +F: Documentation/devicetree/bindings/media/samsung,exynos4212-fimc-is.yaml | |
| 18546 | +F: Documentation/devicetree/bindings/media/samsung,exynos4212-fimc-lite.yaml | |
| 18547 | +F: Documentation/devicetree/bindings/media/samsung,fimc.yaml | |
| 18563 | 18548 | F: drivers/media/platform/samsung/exynos4-is/ |
| 18564 | 18549 | |
| 18565 | 18550 | SAMSUNG SOC CLOCK DRIVERS |
| @@ -19038,6 +19023,7 @@ L: linux-media@vger.kernel.org · 472 unmodified lines | ||
| 19038 | 19023 | S: Odd Fixes |
| 19039 | 19024 | W: https://linuxtv.org |
| 19040 | 19025 | T: git git://linuxtv.org/media_tree.git |
| 19026 | +F: Documentation/devicetree/bindings/media/silabs,si470x.yaml | |
| 19041 | 19027 | F: drivers/media/radio/si470x/radio-si470x-i2c.c |
| 19042 | 19028 | |
| 19043 | 19029 | SI470X FM RADIO RECEIVER USB DRIVER |
| @@ -1052,6 +1052,7 @@ void cec_received_msg_ts(struct cec_adapter *adap, · 1051 unmodified lines | ||
| 1052 | 1052 | u8 cmd = msg->msg[1]; |
| 1053 | 1053 | bool is_reply = false; |
| 1054 | 1054 | bool valid_la = true; |
| 1055 | + bool monitor_valid_la = true; | |
| 1055 | 1056 | u8 min_len = 0; |
| 1056 | 1057 | |
| 1057 | 1058 | if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE)) |
| @@ -1093,8 +1094,10 @@ void cec_received_msg_ts(struct cec_adapter *adap, · 35 unmodified lines | ||
| 1093 | 1094 | adap->last_initiator = 0xff; |
| 1094 | 1095 | |
| 1095 | 1096 | /* Check if this message was for us (directed or broadcast). */ |
| 1096 | − if (!cec_msg_is_broadcast(msg)) | |
| 1097 | + if (!cec_msg_is_broadcast(msg)) { | |
| 1097 | 1098 | valid_la = cec_has_log_addr(adap, msg_dest); |
| 1099 | + monitor_valid_la = valid_la; | |
| 1100 | + } | |
| 1098 | 1101 | |
| 1099 | 1102 | /* |
| 1100 | 1103 | * Check if the length is not too short or if the message is a |
| @@ -1227,7 +1230,7 @@ void cec_received_msg_ts(struct cec_adapter *adap, · 126 unmodified lines | ||
| 1227 | 1230 | mutex_unlock(&adap->lock); |
| 1228 | 1231 | |
| 1229 | 1232 | /* Pass the message on to any monitoring filehandles */ |
| 1230 | − cec_queue_msg_monitor(adap, msg, valid_la); | |
| 1233 | + cec_queue_msg_monitor(adap, msg, monitor_valid_la); | |
| 1231 | 1234 | |
| 1232 | 1235 | /* We're done if it is not for us or a poll message */ |
| 1233 | 1236 | if (!valid_la || msg->len <= 1) |
| @@ -269,13 +269,12 @@ del_adap: · 268 unmodified lines | ||
| 269 | 269 | return ret; |
| 270 | 270 | } |
| 271 | 271 | |
| 272 | −static int cec_gpio_remove(struct platform_device *pdev) | |
| 272 | +static void cec_gpio_remove(struct platform_device *pdev) | |
| 273 | 273 | { |
| 274 | 274 | struct cec_gpio *cec = platform_get_drvdata(pdev); |
| 275 | 275 | |
| 276 | 276 | cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); |
| 277 | 277 | cec_unregister_adapter(cec->adap); |
| 278 | − return 0; | |
| 279 | 278 | } |
| 280 | 279 | |
| 281 | 280 | static const struct of_device_id cec_gpio_match[] = { |
| @@ -288,7 +287,7 @@ MODULE_DEVICE_TABLE(of, cec_gpio_match); · 6 unmodified lines | ||
| 288 | 287 | |
| 289 | 288 | static struct platform_driver cec_gpio_pdrv = { |
| 290 | 289 | .probe = cec_gpio_probe, |
| 291 | − .remove = cec_gpio_remove, | |
| 290 | + .remove_new = cec_gpio_remove, | |
| 292 | 291 | .driver = { |
| 293 | 292 | .name = "cec-gpio", |
| 294 | 293 | .of_match_table = cec_gpio_match, |
| @@ -225,6 +225,12 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { · 224 unmodified lines | ||
| 225 | 225 | { "Google", "Kinox", "0000:00:02.0", "Port B" }, |
| 226 | 226 | /* Google Kuldax */ |
| 227 | 227 | { "Google", "Kuldax", "0000:00:02.0", "Port B" }, |
| 228 | + /* Google Aurash */ | |
| 229 | + { "Google", "Aurash", "0000:00:02.0", "Port B" }, | |
| 230 | + /* Google Gladios */ | |
| 231 | + { "Google", "Gladios", "0000:00:02.0", "Port B" }, | |
| 232 | + /* Google Lisbon */ | |
| 233 | + { "Google", "Lisbon", "0000:00:02.0", "Port B" }, | |
| 228 | 234 | }; |
| 229 | 235 | |
| 230 | 236 | static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, |
| @@ -326,31 +332,31 @@ out_probe_adapter: · 95 unmodified lines | ||
| 326 | 332 | return ret; |
| 327 | 333 | } |
| 328 | 334 | |
| 329 | −static int cros_ec_cec_remove(struct platform_device *pdev) | |
| 335 | +static void cros_ec_cec_remove(struct platform_device *pdev) | |
| 330 | 336 | { |
| 331 | 337 | struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); |
| 332 | 338 | struct device *dev = &pdev->dev; |
| 333 | 339 | int ret; |
| 334 | 340 | |
| 341 | + /* | |
| 342 | + * blocking_notifier_chain_unregister() only fails if the notifier isn't | |
| 343 | + * in the list. We know it was added to it by .probe(), so there should | |
| 344 | + * be no need for error checking. Be cautious and still check. | |
| 345 | + */ | |
| 335 | 346 | ret = blocking_notifier_chain_unregister( |
| 336 | 347 | &cros_ec_cec->cros_ec->event_notifier, |
| 337 | 348 | &cros_ec_cec->notifier); |
| 338 | − | |
| 339 | − if (ret) { | |
| 349 | + if (ret) | |
| 340 | 350 | dev_err(dev, "failed to unregister notifier\n"); |
| 341 | − return ret; | |
| 342 | − } | |
| 343 | 351 | |
| 344 | 352 | cec_notifier_cec_adap_unregister(cros_ec_cec->notify, |
| 345 | 353 | cros_ec_cec->adap); |
| 346 | 354 | cec_unregister_adapter(cros_ec_cec->adap); |
| 347 | − | |
| 348 | − return 0; | |
| 349 | 355 | } |
| 350 | 356 | |
| 351 | 357 | static struct platform_driver cros_ec_cec_driver = { |
| 352 | 358 | .probe = cros_ec_cec_probe, |
| 353 | − .remove = cros_ec_cec_remove, | |
| 359 | + .remove_new = cros_ec_cec_remove, | |
| 354 | 360 | .driver = { |
| 355 | 361 | .name = DRV_NAME, |
| 356 | 362 | .pm = &cros_ec_cec_pm_ops, |
| @@ -744,7 +744,7 @@ out_probe_adapter: · 743 unmodified lines | ||
| 744 | 744 | return ret; |
| 745 | 745 | } |
| 746 | 746 | |
| 747 | −static int meson_ao_cec_g12a_remove(struct platform_device *pdev) | |
| 747 | +static void meson_ao_cec_g12a_remove(struct platform_device *pdev) | |
| 748 | 748 | { |
| 749 | 749 | struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev); |
| 750 | 750 | |
| @@ -753,8 +753,6 @@ static int meson_ao_cec_g12a_remove(struct platform_device *pdev) · 2 unmodified lines | ||
| 753 | 753 | cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); |
| 754 | 754 | |
| 755 | 755 | cec_unregister_adapter(ao_cec->adap); |
| 756 | − | |
| 757 | − return 0; | |
| 758 | 756 | } |
| 759 | 757 | |
| 760 | 758 | static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = { |
| @@ -780,7 +778,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); · 19 unmodified lines | ||
| 780 | 778 | |
| 781 | 779 | static struct platform_driver meson_ao_cec_g12a_driver = { |
| 782 | 780 | .probe = meson_ao_cec_g12a_probe, |
| 783 | − .remove = meson_ao_cec_g12a_remove, | |
| 781 | + .remove_new = meson_ao_cec_g12a_remove, | |
| 784 | 782 | .driver = { |
| 785 | 783 | .name = "meson-ao-cec-g12a", |
| 786 | 784 | .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), |
| @@ -696,7 +696,7 @@ out_probe_adapter: · 695 unmodified lines | ||
| 696 | 696 | return ret; |
| 697 | 697 | } |
| 698 | 698 | |
| 699 | −static int meson_ao_cec_remove(struct platform_device *pdev) | |
| 699 | +static void meson_ao_cec_remove(struct platform_device *pdev) | |
| 700 | 700 | { |
| 701 | 701 | struct meson_ao_cec_device *ao_cec = platform_get_drvdata(pdev); |
| 702 | 702 | |
| @@ -704,8 +704,6 @@ static int meson_ao_cec_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 704 | 704 | |
| 705 | 705 | cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); |
| 706 | 706 | cec_unregister_adapter(ao_cec->adap); |
| 707 | − | |
| 708 | − return 0; | |
| 709 | 707 | } |
| 710 | 708 | |
| 711 | 709 | static const struct of_device_id meson_ao_cec_of_match[] = { |
| @@ -716,7 +714,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match); · 4 unmodified lines | ||
| 716 | 714 | |
| 717 | 715 | static struct platform_driver meson_ao_cec_driver = { |
| 718 | 716 | .probe = meson_ao_cec_probe, |
| 719 | − .remove = meson_ao_cec_remove, | |
| 717 | + .remove_new = meson_ao_cec_remove, | |
| 720 | 718 | .driver = { |
| 721 | 719 | .name = "meson-ao-cec", |
| 722 | 720 | .of_match_table = of_match_ptr(meson_ao_cec_of_match), |
| @@ -249,14 +249,13 @@ err_delete_adapter: · 248 unmodified lines | ||
| 249 | 249 | return ret; |
| 250 | 250 | } |
| 251 | 251 | |
| 252 | −static int s5p_cec_remove(struct platform_device *pdev) | |
| 252 | +static void s5p_cec_remove(struct platform_device *pdev) | |
| 253 | 253 | { |
| 254 | 254 | struct s5p_cec_dev *cec = platform_get_drvdata(pdev); |
| 255 | 255 | |
| 256 | 256 | cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); |
| 257 | 257 | cec_unregister_adapter(cec->adap); |
| 258 | 258 | pm_runtime_disable(&pdev->dev); |
| 259 | − return 0; | |
| 260 | 259 | } |
| 261 | 260 | |
| 262 | 261 | static int __maybe_unused s5p_cec_runtime_suspend(struct device *dev) |
| @@ -295,7 +294,7 @@ MODULE_DEVICE_TABLE(of, s5p_cec_match); · 32 unmodified lines | ||
| 295 | 294 | |
| 296 | 295 | static struct platform_driver s5p_cec_pdrv = { |
| 297 | 296 | .probe = s5p_cec_probe, |
| 298 | − .remove = s5p_cec_remove, | |
| 297 | + .remove_new = s5p_cec_remove, | |
| 299 | 298 | .driver = { |
| 300 | 299 | .name = CEC_NAME, |
| 301 | 300 | .of_match_table = s5p_cec_match, |
| @@ -668,7 +668,7 @@ err: · 667 unmodified lines | ||
| 668 | 668 | return ret; |
| 669 | 669 | } |
| 670 | 670 | |
| 671 | −static int secocec_remove(struct platform_device *pdev) | |
| 671 | +static void secocec_remove(struct platform_device *pdev) | |
| 672 | 672 | { |
| 673 | 673 | struct secocec_data *secocec = platform_get_drvdata(pdev); |
| 674 | 674 | u16 val; |
| @@ -686,8 +686,6 @@ static int secocec_remove(struct platform_device *pdev) · 11 unmodified lines | ||
| 686 | 686 | release_region(BRA_SMB_BASE_ADDR, 7); |
| 687 | 687 | |
| 688 | 688 | dev_dbg(&pdev->dev, "CEC device removed\n"); |
| 689 | − | |
| 690 | − return 0; | |
| 691 | 689 | } |
| 692 | 690 | |
| 693 | 691 | #ifdef CONFIG_PM_SLEEP |
| @@ -780,7 +778,7 @@ static struct platform_driver secocec_driver = { · 86 unmodified lines | ||
| 780 | 778 | .pm = SECOCEC_PM_OPS, |
| 781 | 779 | }, |
| 782 | 780 | .probe = secocec_probe, |
| 783 | − .remove = secocec_remove, | |
| 781 | + .remove_new = secocec_remove, | |
| 784 | 782 | }; |
| 785 | 783 | |
| 786 | 784 | module_platform_driver(secocec_driver); |
| @@ -364,14 +364,12 @@ err_delete_adapter: · 363 unmodified lines | ||
| 364 | 364 | return ret; |
| 365 | 365 | } |
| 366 | 366 | |
| 367 | −static int stih_cec_remove(struct platform_device *pdev) | |
| 367 | +static void stih_cec_remove(struct platform_device *pdev) | |
| 368 | 368 | { |
| 369 | 369 | struct stih_cec *cec = platform_get_drvdata(pdev); |
| 370 | 370 | |
| 371 | 371 | cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); |
| 372 | 372 | cec_unregister_adapter(cec->adap); |
| 373 | − | |
| 374 | − return 0; | |
| 375 | 373 | } |
| 376 | 374 | |
| 377 | 375 | static const struct of_device_id stih_cec_match[] = { |
| @@ -384,7 +382,7 @@ MODULE_DEVICE_TABLE(of, stih_cec_match); · 6 unmodified lines | ||
| 384 | 382 | |
| 385 | 383 | static struct platform_driver stih_cec_pdrv = { |
| 386 | 384 | .probe = stih_cec_probe, |
| 387 | − .remove = stih_cec_remove, | |
| 385 | + .remove_new = stih_cec_remove, | |
| 388 | 386 | .driver = { |
| 389 | 387 | .name = CEC_NAME, |
| 390 | 388 | .of_match_table = stih_cec_match, |
| @@ -344,7 +344,7 @@ err_unprepare_cec_clk: · 343 unmodified lines | ||
| 344 | 344 | return ret; |
| 345 | 345 | } |
| 346 | 346 | |
| 347 | −static int stm32_cec_remove(struct platform_device *pdev) | |
| 347 | +static void stm32_cec_remove(struct platform_device *pdev) | |
| 348 | 348 | { |
| 349 | 349 | struct stm32_cec *cec = platform_get_drvdata(pdev); |
| 350 | 350 | |
| @@ -352,8 +352,6 @@ static int stm32_cec_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 352 | 352 | clk_unprepare(cec->clk_hdmi_cec); |
| 353 | 353 | |
| 354 | 354 | cec_unregister_adapter(cec->adap); |
| 355 | − | |
| 356 | − return 0; | |
| 357 | 355 | } |
| 358 | 356 | |
| 359 | 357 | static const struct of_device_id stm32_cec_of_match[] = { |
| @@ -364,7 +362,7 @@ MODULE_DEVICE_TABLE(of, stm32_cec_of_match); · 4 unmodified lines | ||
| 364 | 362 | |
| 365 | 363 | static struct platform_driver stm32_cec_driver = { |
| 366 | 364 | .probe = stm32_cec_probe, |
| 367 | − .remove = stm32_cec_remove, | |
| 365 | + .remove_new = stm32_cec_remove, | |
| 368 | 366 | .driver = { |
| 369 | 367 | .name = CEC_NAME, |
| 370 | 368 | .of_match_table = stm32_cec_of_match, |
| @@ -421,7 +421,7 @@ err_clk: · 420 unmodified lines | ||
| 421 | 421 | return ret; |
| 422 | 422 | } |
| 423 | 423 | |
| 424 | −static int tegra_cec_remove(struct platform_device *pdev) | |
| 424 | +static void tegra_cec_remove(struct platform_device *pdev) | |
| 425 | 425 | { |
| 426 | 426 | struct tegra_cec *cec = platform_get_drvdata(pdev); |
| 427 | 427 | |
| @@ -429,8 +429,6 @@ static int tegra_cec_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 429 | 429 | |
| 430 | 430 | cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); |
| 431 | 431 | cec_unregister_adapter(cec->adap); |
| 432 | − | |
| 433 | − return 0; | |
| 434 | 432 | } |
| 435 | 433 | |
| 436 | 434 | #ifdef CONFIG_PM |
| @@ -467,7 +465,7 @@ static struct platform_driver tegra_cec_driver = { · 30 unmodified lines | ||
| 467 | 465 | .of_match_table = of_match_ptr(tegra_cec_of_match), |
| 468 | 466 | }, |
| 469 | 467 | .probe = tegra_cec_probe, |
| 470 | − .remove = tegra_cec_remove, | |
| 468 | + .remove_new = tegra_cec_remove, | |
| 471 | 469 | |
| 472 | 470 | #ifdef CONFIG_PM |
| 473 | 471 | .suspend = tegra_cec_suspend, |
| @@ -1,29 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −/* | |
| 3 | − */ | |
| 4 | −struct btcx_riscmem { | |
| 5 | − unsigned int size; | |
| 6 | − __le32 *cpu; | |
| 7 | − __le32 *jmp; | |
| 8 | − dma_addr_t dma; | |
| 9 | −}; | |
| 10 | − | |
| 11 | −struct btcx_skiplist { | |
| 12 | − int start; | |
| 13 | − int end; | |
| 14 | −}; | |
| 15 | − | |
| 16 | −int btcx_riscmem_alloc(struct pci_dev *pci, | |
| 17 | − struct btcx_riscmem *risc, | |
| 18 | − unsigned int size); | |
| 19 | −void btcx_riscmem_free(struct pci_dev *pci, | |
| 20 | − struct btcx_riscmem *risc); | |
| 21 | − | |
| 22 | −int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, | |
| 23 | − struct v4l2_clip *clips, unsigned int n); | |
| 24 | −int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, | |
| 25 | − unsigned int n, int mask); | |
| 26 | −void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); | |
| 27 | −void btcx_calc_skips(int line, int width, int *maxy, | |
| 28 | − struct btcx_skiplist *skips, unsigned int *nskips, | |
| 29 | − const struct v4l2_clip *clips, unsigned int nclips); | |
| @@ -6,5 +6,5 @@ config VIDEO_SAA7146 · 5 unmodified lines | ||
| 6 | 6 | config VIDEO_SAA7146_VV |
| 7 | 7 | tristate |
| 8 | 8 | depends on VIDEO_DEV |
| 9 | − select VIDEOBUF_DMA_SG | |
| 9 | + select VIDEOBUF2_DMA_SG | |
| 10 | 10 | select VIDEO_SAA7146 |
| @@ -37,7 +37,8 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) · 36 unmodified lines | ||
| 37 | 37 | { |
| 38 | 38 | u32 value = 0; |
| 39 | 39 | |
| 40 | − BUG_ON(port > 3); | |
| 40 | + if (WARN_ON(port > 3)) | |
| 41 | + return; | |
| 41 | 42 | |
| 42 | 43 | value = saa7146_read(dev, GPIO_CTRL); |
| 43 | 44 | value &= ~(0xff << (8*port)); |
| @@ -148,7 +149,8 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) · 104 unmodified lines | ||
| 148 | 149 | pg = vmalloc_to_page(virt); |
| 149 | 150 | if (NULL == pg) |
| 150 | 151 | goto err; |
| 151 | − BUG_ON(PageHighMem(pg)); | |
| 152 | + if (WARN_ON(PageHighMem(pg))) | |
| 153 | + return NULL; | |
| 152 | 154 | sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); |
| 153 | 155 | } |
| 154 | 156 | return sglist; |
| @@ -233,46 +235,32 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) · 78 unmodified lines | ||
| 233 | 235 | } |
| 234 | 236 | |
| 235 | 237 | int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, |
| 236 | − struct scatterlist *list, int sglen ) | |
| 238 | + struct scatterlist *list, int sglen) | |
| 237 | 239 | { |
| 240 | + struct sg_dma_page_iter dma_iter; | |
| 238 | 241 | __le32 *ptr, fill; |
| 239 | 242 | int nr_pages = 0; |
| 240 | − int i,p; | |
| 243 | + int i; | |
| 241 | 244 | |
| 242 | − BUG_ON(0 == sglen); | |
| 243 | − BUG_ON(list->offset > PAGE_SIZE); | |
| 245 | + if (WARN_ON(!sglen) || | |
| 246 | + WARN_ON(list->offset > PAGE_SIZE)) | |
| 247 | + return -EIO; | |
| 244 | 248 | |
| 245 | 249 | /* if we have a user buffer, the first page may not be |
| 246 | 250 | aligned to a page boundary. */ |
| 247 | 251 | pt->offset = list->offset; |
| 248 | 252 | |
| 249 | 253 | ptr = pt->cpu; |
| 250 | − for (i = 0; i < sglen; i++, list++) { | |
| 251 | −/* | |
| 252 | − pr_debug("i:%d, adr:0x%08x, len:%d, offset:%d\n", | |
| 253 | − i, sg_dma_address(list), sg_dma_len(list), | |
| 254 | − list->offset); | |
| 255 | −*/ | |
| 256 | − for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr++) { | |
| 257 | − *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096); | |
| 258 | − nr_pages++; | |
| 259 | − } | |
| 254 | + for_each_sg_dma_page(list, &dma_iter, sglen, 0) { | |
| 255 | + *ptr++ = cpu_to_le32(sg_page_iter_dma_address(&dma_iter)); | |
| 256 | + nr_pages++; | |
| 260 | 257 | } |
| 261 | 258 | |
| 262 | 259 | |
| 263 | 260 | /* safety; fill the page table up with the last valid page */ |
| 264 | 261 | fill = *(ptr-1); |
| 265 | − for(i=nr_pages;i<1024;i++) { | |
| 262 | + for (i = nr_pages; i < 1024; i++) | |
| 266 | 263 | *ptr++ = fill; |
| 267 | − } | |
| 268 | − | |
| 269 | −/* | |
| 270 | − ptr = pt->cpu; | |
| 271 | − pr_debug("offset: %d\n", pt->offset); | |
| 272 | − for(i=0;i<5;i++) { | |
| 273 | − pr_debug("ptr1 %d: 0x%08x\n", i, ptr[i]); | |
| 274 | − } | |
| 275 | −*/ | |
| 276 | 264 | return 0; |
| 277 | 265 | } |
| 278 | 266 | |
| @@ -7,12 +7,11 @@ · 6 unmodified lines | ||
| 7 | 7 | /****************************************************************************/ |
| 8 | 8 | /* resource management functions, shamelessly stolen from saa7134 driver */ |
| 9 | 9 | |
| 10 | −int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) | |
| 10 | +int saa7146_res_get(struct saa7146_dev *dev, unsigned int bit) | |
| 11 | 11 | { |
| 12 | − struct saa7146_dev *dev = fh->dev; | |
| 13 | 12 | struct saa7146_vv *vv = dev->vv_data; |
| 14 | 13 | |
| 15 | − if (fh->resources & bit) { | |
| 14 | + if (vv->resources & bit) { | |
| 16 | 15 | DEB_D("already allocated! want: 0x%02x, cur:0x%02x\n", |
| 17 | 16 | bit, vv->resources); |
| 18 | 17 | /* have it already allocated */ |
| @@ -27,41 +26,22 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit) · 8 unmodified lines | ||
| 27 | 26 | return 0; |
| 28 | 27 | } |
| 29 | 28 | /* it's free, grab it */ |
| 30 | − fh->resources |= bit; | |
| 31 | 29 | vv->resources |= bit; |
| 32 | 30 | DEB_D("res: get 0x%02x, cur:0x%02x\n", bit, vv->resources); |
| 33 | 31 | return 1; |
| 34 | 32 | } |
| 35 | 33 | |
| 36 | −void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) | |
| 34 | +void saa7146_res_free(struct saa7146_dev *dev, unsigned int bits) | |
| 37 | 35 | { |
| 38 | − struct saa7146_dev *dev = fh->dev; | |
| 39 | 36 | struct saa7146_vv *vv = dev->vv_data; |
| 40 | 37 | |
| 41 | − BUG_ON((fh->resources & bits) != bits); | |
| 38 | + WARN_ON((vv->resources & bits) != bits); | |
| 42 | 39 | |
| 43 | − fh->resources &= ~bits; | |
| 44 | 40 | vv->resources &= ~bits; |
| 45 | 41 | DEB_D("res: put 0x%02x, cur:0x%02x\n", bits, vv->resources); |
| 46 | 42 | } |
| 47 | 43 | |
| 48 | 44 | |
| 49 | −/********************************************************************************/ | |
| 50 | −/* common dma functions */ | |
| 51 | − | |
| 52 | −void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, | |
| 53 | − struct saa7146_buf *buf) | |
| 54 | −{ | |
| 55 | − struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | |
| 56 | − DEB_EE("dev:%p, buf:%p\n", dev, buf); | |
| 57 | − | |
| 58 | − videobuf_waiton(q, &buf->vb, 0, 0); | |
| 59 | − videobuf_dma_unmap(q->dev, dma); | |
| 60 | − videobuf_dma_free(dma); | |
| 61 | − buf->vb.state = VIDEOBUF_NEEDS_INIT; | |
| 62 | −} | |
| 63 | − | |
| 64 | − | |
| 65 | 45 | /********************************************************************************/ |
| 66 | 46 | /* common buffer functions */ |
| 67 | 47 | |
| @@ -72,15 +52,15 @@ int saa7146_buffer_queue(struct saa7146_dev *dev, · 4 unmodified lines | ||
| 72 | 52 | assert_spin_locked(&dev->slock); |
| 73 | 53 | DEB_EE("dev:%p, dmaq:%p, buf:%p\n", dev, q, buf); |
| 74 | 54 | |
| 75 | − BUG_ON(!q); | |
| 55 | + if (WARN_ON(!q)) | |
| 56 | + return -EIO; | |
| 76 | 57 | |
| 77 | 58 | if (NULL == q->curr) { |
| 78 | 59 | q->curr = buf; |
| 79 | 60 | DEB_D("immediately activating buffer %p\n", buf); |
| 80 | 61 | buf->activate(dev,buf,NULL); |
| 81 | 62 | } else { |
| 82 | − list_add_tail(&buf->vb.queue,&q->queue); | |
| 83 | − buf->vb.state = VIDEOBUF_QUEUED; | |
| 63 | + list_add_tail(&buf->list, &q->queue); | |
| 84 | 64 | DEB_D("adding buffer %p to queue. (active buffer present)\n", |
| 85 | 65 | buf); |
| 86 | 66 | } |
| @@ -91,21 +71,31 @@ void saa7146_buffer_finish(struct saa7146_dev *dev, · 4 unmodified lines | ||
| 91 | 71 | struct saa7146_dmaqueue *q, |
| 92 | 72 | int state) |
| 93 | 73 | { |
| 74 | + struct saa7146_vv *vv = dev->vv_data; | |
| 75 | + struct saa7146_buf *buf = q->curr; | |
| 76 | + | |
| 94 | 77 | assert_spin_locked(&dev->slock); |
| 95 | 78 | DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state); |
| 96 | 79 | DEB_EE("q->curr:%p\n", q->curr); |
| 97 | 80 | |
| 98 | 81 | /* finish current buffer */ |
| 99 | − if (NULL == q->curr) { | |
| 82 | + if (!buf) { | |
| 100 | 83 | DEB_D("aiii. no current buffer\n"); |
| 101 | 84 | return; |
| 102 | 85 | } |
| 103 | 86 | |
| 104 | − q->curr->vb.state = state; | |
| 105 | − q->curr->vb.ts = ktime_get_ns(); | |
| 106 | − wake_up(&q->curr->vb.done); | |
| 107 | − | |
| 108 | 87 | q->curr = NULL; |
| 88 | + buf->vb.vb2_buf.timestamp = ktime_get_ns(); | |
| 89 | + if (vv->video_fmt.field == V4L2_FIELD_ALTERNATE) | |
| 90 | + buf->vb.field = vv->last_field; | |
| 91 | + else if (vv->video_fmt.field == V4L2_FIELD_ANY) | |
| 92 | + buf->vb.field = (vv->video_fmt.height > vv->standard->v_max_out / 2) | |
| 93 | + ? V4L2_FIELD_INTERLACED | |
| 94 | + : V4L2_FIELD_BOTTOM; | |
| 95 | + else | |
| 96 | + buf->vb.field = vv->video_fmt.field; | |
| 97 | + buf->vb.sequence = vv->seqnr++; | |
| 98 | + vb2_buffer_done(&buf->vb.vb2_buf, state); | |
| 109 | 99 | } |
| 110 | 100 | |
| 111 | 101 | void saa7146_buffer_next(struct saa7146_dev *dev, |
| @@ -113,17 +103,18 @@ void saa7146_buffer_next(struct saa7146_dev *dev, · 1 unmodified line | ||
| 113 | 103 | { |
| 114 | 104 | struct saa7146_buf *buf,*next = NULL; |
| 115 | 105 | |
| 116 | − BUG_ON(!q); | |
| 106 | + if (WARN_ON(!q)) | |
| 107 | + return; | |
| 117 | 108 | |
| 118 | 109 | DEB_INT("dev:%p, dmaq:%p, vbi:%d\n", dev, q, vbi); |
| 119 | 110 | |
| 120 | 111 | assert_spin_locked(&dev->slock); |
| 121 | 112 | if (!list_empty(&q->queue)) { |
| 122 | 113 | /* activate next one from queue */ |
| 123 | − buf = list_entry(q->queue.next,struct saa7146_buf,vb.queue); | |
| 124 | − list_del(&buf->vb.queue); | |
| 114 | + buf = list_entry(q->queue.next, struct saa7146_buf, list); | |
| 115 | + list_del(&buf->list); | |
| 125 | 116 | if (!list_empty(&q->queue)) |
| 126 | − next = list_entry(q->queue.next,struct saa7146_buf, vb.queue); | |
| 117 | + next = list_entry(q->queue.next, struct saa7146_buf, list); | |
| 127 | 118 | q->curr = buf; |
| 128 | 119 | DEB_INT("next buffer: buf:%p, prev:%p, next:%p\n", |
| 129 | 120 | buf, q->queue.prev, q->queue.next); |
| @@ -171,7 +162,7 @@ void saa7146_buffer_timeout(struct timer_list *t) · 41 unmodified lines | ||
| 171 | 162 | spin_lock_irqsave(&dev->slock,flags); |
| 172 | 163 | if (q->curr) { |
| 173 | 164 | DEB_D("timeout on %p\n", q->curr); |
| 174 | − saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); | |
| 165 | + saa7146_buffer_finish(dev, q, VB2_BUF_STATE_ERROR); | |
| 175 | 166 | } |
| 176 | 167 | |
| 177 | 168 | /* we don't restart the transfer here like other drivers do. when |
| @@ -180,256 +171,39 @@ void saa7146_buffer_timeout(struct timer_list *t) · 2 unmodified lines | ||
| 180 | 171 | we mess up our capture logic. if a timeout occurs on another buffer, |
| 181 | 172 | then something is seriously broken before, so no need to buffer the |
| 182 | 173 | next capture IMHO... */ |
| 183 | −/* | |
| 184 | − saa7146_buffer_next(dev,q); | |
| 185 | −*/ | |
| 174 | + | |
| 175 | + saa7146_buffer_next(dev, q, 0); | |
| 176 | + | |
| 186 | 177 | spin_unlock_irqrestore(&dev->slock,flags); |
| 187 | 178 | } |
| 188 | 179 | |
| 189 | 180 | /********************************************************************************/ |
| 190 | 181 | /* file operations */ |
| 191 | 182 | |
| 192 | −static int fops_open(struct file *file) | |
| 183 | +static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) | |
| 193 | 184 | { |
| 194 | 185 | struct video_device *vdev = video_devdata(file); |
| 195 | 186 | struct saa7146_dev *dev = video_drvdata(file); |
| 196 | − struct saa7146_fh *fh = NULL; | |
| 197 | − int result = 0; | |
| 198 | − | |
| 199 | − DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev)); | |
| 200 | − | |
| 201 | − if (mutex_lock_interruptible(vdev->lock)) | |
| 202 | − return -ERESTARTSYS; | |
| 203 | − | |
| 204 | − DEB_D("using: %p\n", dev); | |
| 205 | − | |
| 206 | − /* check if an extension is registered */ | |
| 207 | − if( NULL == dev->ext ) { | |
| 208 | − DEB_S("no extension registered for this device\n"); | |
| 209 | − result = -ENODEV; | |
| 210 | − goto out; | |
| 211 | − } | |
| 212 | − | |
| 213 | − /* allocate per open data */ | |
| 214 | − fh = kzalloc(sizeof(*fh),GFP_KERNEL); | |
| 215 | − if (NULL == fh) { | |
| 216 | − DEB_S("cannot allocate memory for per open data\n"); | |
| 217 | − result = -ENOMEM; | |
| 218 | − goto out; | |
| 219 | − } | |
| 220 | − | |
| 221 | − v4l2_fh_init(&fh->fh, vdev); | |
| 222 | − | |
| 223 | − file->private_data = &fh->fh; | |
| 224 | − fh->dev = dev; | |
| 225 | − | |
| 226 | − if (vdev->vfl_type == VFL_TYPE_VBI) { | |
| 227 | − DEB_S("initializing vbi...\n"); | |
| 228 | − if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | |
| 229 | − result = saa7146_vbi_uops.open(dev,file); | |
| 230 | − if (dev->ext_vv_data->vbi_fops.open) | |
| 231 | − dev->ext_vv_data->vbi_fops.open(file); | |
| 232 | − } else { | |
| 233 | − DEB_S("initializing video...\n"); | |
| 234 | − result = saa7146_video_uops.open(dev,file); | |
| 235 | − } | |
| 236 | − | |
| 237 | − if (0 != result) { | |
| 238 | − goto out; | |
| 239 | − } | |
| 240 | − | |
| 241 | − if( 0 == try_module_get(dev->ext->module)) { | |
| 242 | − result = -EINVAL; | |
| 243 | − goto out; | |
| 244 | − } | |
| 245 | − | |
| 246 | − result = 0; | |
| 247 | − v4l2_fh_add(&fh->fh); | |
| 248 | −out: | |
| 249 | − if (fh && result != 0) { | |
| 250 | − kfree(fh); | |
| 251 | − file->private_data = NULL; | |
| 252 | − } | |
| 253 | − mutex_unlock(vdev->lock); | |
| 254 | − return result; | |
| 255 | −} | |
| 256 | − | |
| 257 | −static int fops_release(struct file *file) | |
| 258 | −{ | |
| 259 | − struct video_device *vdev = video_devdata(file); | |
| 260 | − struct saa7146_fh *fh = file->private_data; | |
| 261 | − struct saa7146_dev *dev = fh->dev; | |
| 262 | − | |
| 263 | − DEB_EE("file:%p\n", file); | |
| 264 | − | |
| 265 | − mutex_lock(vdev->lock); | |
| 266 | − | |
| 267 | − if (vdev->vfl_type == VFL_TYPE_VBI) { | |
| 268 | − if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) | |
| 269 | − saa7146_vbi_uops.release(dev,file); | |
| 270 | − if (dev->ext_vv_data->vbi_fops.release) | |
| 271 | − dev->ext_vv_data->vbi_fops.release(file); | |
| 272 | − } else { | |
| 273 | − saa7146_video_uops.release(dev,file); | |
| 274 | − } | |
| 275 | − | |
| 276 | − v4l2_fh_del(&fh->fh); | |
| 277 | − v4l2_fh_exit(&fh->fh); | |
| 278 | − module_put(dev->ext->module); | |
| 279 | − file->private_data = NULL; | |
| 280 | − kfree(fh); | |
| 281 | − | |
| 282 | − mutex_unlock(vdev->lock); | |
| 283 | − | |
| 284 | − return 0; | |
| 285 | −} | |
| 286 | − | |
| 287 | −static int fops_mmap(struct file *file, struct vm_area_struct * vma) | |
| 288 | −{ | |
| 289 | − struct video_device *vdev = video_devdata(file); | |
| 290 | − struct saa7146_fh *fh = file->private_data; | |
| 291 | − struct videobuf_queue *q; | |
| 292 | − int res; | |
| 293 | − | |
| 294 | − switch (vdev->vfl_type) { | |
| 295 | − case VFL_TYPE_VIDEO: { | |
| 296 | − DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n", | |
| 297 | − file, vma); | |
| 298 | − q = &fh->video_q; | |
| 299 | − break; | |
| 300 | − } | |
| 301 | − case VFL_TYPE_VBI: { | |
| 302 | − DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n", | |
| 303 | − file, vma); | |
| 304 | − if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) | |
| 305 | − return -ENODEV; | |
| 306 | − q = &fh->vbi_q; | |
| 307 | − break; | |
| 308 | − } | |
| 309 | − default: | |
| 310 | − BUG(); | |
| 311 | − } | |
| 187 | + int ret; | |
| 312 | 188 | |
| 189 | + if (vdev->vfl_type != VFL_TYPE_VBI || !dev->ext_vv_data->vbi_fops.write) | |
| 190 | + return -EINVAL; | |
| 313 | 191 | if (mutex_lock_interruptible(vdev->lock)) |
| 314 | 192 | return -ERESTARTSYS; |
| 315 | − res = videobuf_mmap_mapper(q, vma); | |
| 193 | + ret = dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); | |
| 316 | 194 | mutex_unlock(vdev->lock); |
| 317 | − return res; | |
| 318 | −} | |
| 319 | − | |
| 320 | −static __poll_t __fops_poll(struct file *file, struct poll_table_struct *wait) | |
| 321 | −{ | |
| 322 | − struct video_device *vdev = video_devdata(file); | |
| 323 | − struct saa7146_fh *fh = file->private_data; | |
| 324 | − struct videobuf_buffer *buf = NULL; | |
| 325 | − struct videobuf_queue *q; | |
| 326 | − __poll_t res = v4l2_ctrl_poll(file, wait); | |
| 327 | − | |
| 328 | − DEB_EE("file:%p, poll:%p\n", file, wait); | |
| 329 | − | |
| 330 | − if (vdev->vfl_type == VFL_TYPE_VBI) { | |
| 331 | − if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) | |
| 332 | − return res | EPOLLOUT | EPOLLWRNORM; | |
| 333 | − if( 0 == fh->vbi_q.streaming ) | |
| 334 | − return res | videobuf_poll_stream(file, &fh->vbi_q, wait); | |
| 335 | − q = &fh->vbi_q; | |
| 336 | − } else { | |
| 337 | − DEB_D("using video queue\n"); | |
| 338 | − q = &fh->video_q; | |
| 339 | − } | |
| 340 | − | |
| 341 | − if (!list_empty(&q->stream)) | |
| 342 | − buf = list_entry(q->stream.next, struct videobuf_buffer, stream); | |
| 343 | − | |
| 344 | − if (!buf) { | |
| 345 | − DEB_D("buf == NULL!\n"); | |
| 346 | − return res | EPOLLERR; | |
| 347 | − } | |
| 348 | − | |
| 349 | − poll_wait(file, &buf->done, wait); | |
| 350 | − if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { | |
| 351 | − DEB_D("poll succeeded!\n"); | |
| 352 | − return res | EPOLLIN | EPOLLRDNORM; | |
| 353 | − } | |
| 354 | − | |
| 355 | − DEB_D("nothing to poll for, buf->state:%d\n", buf->state); | |
| 356 | − return res; | |
| 357 | −} | |
| 358 | − | |
| 359 | −static __poll_t fops_poll(struct file *file, struct poll_table_struct *wait) | |
| 360 | −{ | |
| 361 | − struct video_device *vdev = video_devdata(file); | |
| 362 | − __poll_t res; | |
| 363 | − | |
| 364 | − mutex_lock(vdev->lock); | |
| 365 | − res = __fops_poll(file, wait); | |
| 366 | − mutex_unlock(vdev->lock); | |
| 367 | − return res; | |
| 368 | −} | |
| 369 | − | |
| 370 | −static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | |
| 371 | −{ | |
| 372 | − struct video_device *vdev = video_devdata(file); | |
| 373 | − struct saa7146_fh *fh = file->private_data; | |
| 374 | − int ret; | |
| 375 | − | |
| 376 | − switch (vdev->vfl_type) { | |
| 377 | − case VFL_TYPE_VIDEO: | |
| 378 | −/* | |
| 379 | − DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", | |
| 380 | − file, data, (unsigned long)count); | |
| 381 | −*/ | |
| 382 | − return saa7146_video_uops.read(file,data,count,ppos); | |
| 383 | − case VFL_TYPE_VBI: | |
| 384 | −/* | |
| 385 | − DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n", | |
| 386 | − file, data, (unsigned long)count); | |
| 387 | −*/ | |
| 388 | − if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) { | |
| 389 | − if (mutex_lock_interruptible(vdev->lock)) | |
| 390 | − return -ERESTARTSYS; | |
| 391 | − ret = saa7146_vbi_uops.read(file, data, count, ppos); | |
| 392 | − mutex_unlock(vdev->lock); | |
| 393 | − return ret; | |
| 394 | − } | |
| 395 | − return -EINVAL; | |
| 396 | − default: | |
| 397 | − BUG(); | |
| 398 | − } | |
| 399 | −} | |
| 400 | − | |
| 401 | −static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) | |
| 402 | −{ | |
| 403 | − struct video_device *vdev = video_devdata(file); | |
| 404 | − struct saa7146_fh *fh = file->private_data; | |
| 405 | − int ret; | |
| 406 | − | |
| 407 | − switch (vdev->vfl_type) { | |
| 408 | − case VFL_TYPE_VIDEO: | |
| 409 | − return -EINVAL; | |
| 410 | − case VFL_TYPE_VBI: | |
| 411 | − if (fh->dev->ext_vv_data->vbi_fops.write) { | |
| 412 | − if (mutex_lock_interruptible(vdev->lock)) | |
| 413 | − return -ERESTARTSYS; | |
| 414 | − ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); | |
| 415 | − mutex_unlock(vdev->lock); | |
| 416 | − return ret; | |
| 417 | − } | |
| 418 | − return -EINVAL; | |
| 419 | − default: | |
| 420 | − BUG(); | |
| 421 | − } | |
| 195 | + return ret; | |
| 422 | 196 | } |
| 423 | 197 | |
| 424 | 198 | static const struct v4l2_file_operations video_fops = |
| 425 | 199 | { |
| 426 | 200 | .owner = THIS_MODULE, |
| 427 | − .open = fops_open, | |
| 428 | − .release = fops_release, | |
| 429 | − .read = fops_read, | |
| 201 | + .open = v4l2_fh_open, | |
| 202 | + .release = vb2_fop_release, | |
| 203 | + .read = vb2_fop_read, | |
| 430 | 204 | .write = fops_write, |
| 431 | − .poll = fops_poll, | |
| 432 | − .mmap = fops_mmap, | |
| 205 | + .poll = vb2_fop_poll, | |
| 206 | + .mmap = vb2_fop_mmap, | |
| 433 | 207 | .unlocked_ioctl = video_ioctl2, |
| 434 | 208 | }; |
| 435 | 209 | |
| @@ -516,33 +290,15 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) · 80 unmodified lines | ||
| 516 | 290 | configuration data) */ |
| 517 | 291 | dev->ext_vv_data = ext_vv; |
| 518 | 292 | |
| 519 | − vv->d_clipping.cpu_addr = | |
| 520 | − dma_alloc_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM, | |
| 521 | − &vv->d_clipping.dma_handle, GFP_KERNEL); | |
| 522 | − if( NULL == vv->d_clipping.cpu_addr ) { | |
| 523 | − ERR("out of memory. aborting.\n"); | |
| 524 | − kfree(vv); | |
| 525 | − v4l2_ctrl_handler_free(hdl); | |
| 526 | − v4l2_device_unregister(&dev->v4l2_dev); | |
| 527 | − return -ENOMEM; | |
| 528 | − } | |
| 529 | − | |
| 530 | 293 | saa7146_video_uops.init(dev,vv); |
| 531 | 294 | if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) |
| 532 | 295 | saa7146_vbi_uops.init(dev,vv); |
| 533 | 296 | |
| 534 | − vv->ov_fb.fmt.width = vv->standard->h_max_out; | |
| 535 | − vv->ov_fb.fmt.height = vv->standard->v_max_out; | |
| 536 | − vv->ov_fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565; | |
| 537 | − vv->ov_fb.fmt.bytesperline = 2 * vv->ov_fb.fmt.width; | |
| 538 | − vv->ov_fb.fmt.sizeimage = vv->ov_fb.fmt.bytesperline * vv->ov_fb.fmt.height; | |
| 539 | − vv->ov_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB; | |
| 540 | − | |
| 541 | 297 | fmt = &vv->video_fmt; |
| 542 | 298 | fmt->width = 384; |
| 543 | 299 | fmt->height = 288; |
| 544 | 300 | fmt->pixelformat = V4L2_PIX_FMT_BGR24; |
| 545 | − fmt->field = V4L2_FIELD_ANY; | |
| 301 | + fmt->field = V4L2_FIELD_INTERLACED; | |
| 546 | 302 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 547 | 303 | fmt->bytesperline = 3 * fmt->width; |
| 548 | 304 | fmt->sizeimage = fmt->bytesperline * fmt->height; |
| @@ -561,8 +317,6 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) · 12 unmodified lines | ||
| 561 | 317 | |
| 562 | 318 | timer_setup(&vv->vbi_read_timeout, NULL, 0); |
| 563 | 319 | |
| 564 | − vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING; | |
| 565 | − vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY; | |
| 566 | 320 | dev->vv_data = vv; |
| 567 | 321 | dev->vv_callback = &vv_callback; |
| 568 | 322 | |
| @@ -577,8 +331,6 @@ int saa7146_vv_release(struct saa7146_dev* dev) · 8 unmodified lines | ||
| 577 | 331 | DEB_EE("dev:%p\n", dev); |
| 578 | 332 | |
| 579 | 333 | v4l2_device_unregister(&dev->v4l2_dev); |
| 580 | − dma_free_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM, | |
| 581 | − vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); | |
| 582 | 334 | v4l2_ctrl_handler_free(&dev->ctrl_handler); |
| 583 | 335 | kfree(vv); |
| 584 | 336 | dev->vv_data = NULL; |
| @@ -591,16 +343,20 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release); · 6 unmodified lines | ||
| 591 | 343 | int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, |
| 592 | 344 | char *name, int type) |
| 593 | 345 | { |
| 346 | + struct vb2_queue *q; | |
| 594 | 347 | int err; |
| 595 | 348 | int i; |
| 596 | 349 | |
| 597 | 350 | DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type); |
| 598 | 351 | |
| 599 | 352 | vfd->fops = &video_fops; |
| 600 | − if (type == VFL_TYPE_VIDEO) | |
| 353 | + if (type == VFL_TYPE_VIDEO) { | |
| 601 | 354 | vfd->ioctl_ops = &dev->ext_vv_data->vid_ops; |
| 602 | − else | |
| 355 | + q = &dev->vv_data->video_dmaq.q; | |
| 356 | + } else { | |
| 603 | 357 | vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops; |
| 358 | + q = &dev->vv_data->vbi_dmaq.q; | |
| 359 | + } | |
| 604 | 360 | vfd->release = video_device_release_empty; |
| 605 | 361 | vfd->lock = &dev->v4l2_lock; |
| 606 | 362 | vfd->v4l2_dev = &dev->v4l2_dev; |
| @@ -608,15 +364,36 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, · 1 unmodified line | ||
| 608 | 364 | for (i = 0; i < dev->ext_vv_data->num_stds; i++) |
| 609 | 365 | vfd->tvnorms |= dev->ext_vv_data->stds[i].id; |
| 610 | 366 | strscpy(vfd->name, name, sizeof(vfd->name)); |
| 611 | − vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | | |
| 367 | + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | | |
| 612 | 368 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; |
| 613 | 369 | vfd->device_caps |= dev->ext_vv_data->capabilities; |
| 614 | − if (type == VFL_TYPE_VIDEO) | |
| 370 | + if (type == VFL_TYPE_VIDEO) { | |
| 615 | 371 | vfd->device_caps &= |
| 616 | 372 | ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); |
| 617 | − else | |
| 618 | − vfd->device_caps &= | |
| 619 | − ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO); | |
| 373 | + } else if (vfd->device_caps & V4L2_CAP_SLICED_VBI_OUTPUT) { | |
| 374 | + vfd->vfl_dir = VFL_DIR_TX; | |
| 375 | + vfd->device_caps &= ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | |
| 376 | + V4L2_CAP_AUDIO | V4L2_CAP_TUNER); | |
| 377 | + } else { | |
| 378 | + vfd->device_caps &= ~V4L2_CAP_VIDEO_CAPTURE; | |
| 379 | + } | |
| 380 | + | |
| 381 | + q->type = type == VFL_TYPE_VIDEO ? V4L2_BUF_TYPE_VIDEO_CAPTURE : V4L2_BUF_TYPE_VBI_CAPTURE; | |
| 382 | + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | |
| 383 | + q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; | |
| 384 | + q->ops = type == VFL_TYPE_VIDEO ? &video_qops : &vbi_qops; | |
| 385 | + q->mem_ops = &vb2_dma_sg_memops; | |
| 386 | + q->drv_priv = dev; | |
| 387 | + q->gfp_flags = __GFP_DMA32; | |
| 388 | + q->buf_struct_size = sizeof(struct saa7146_buf); | |
| 389 | + q->lock = &dev->v4l2_lock; | |
| 390 | + q->min_buffers_needed = 2; | |
| 391 | + q->dev = &dev->pci->dev; | |
| 392 | + err = vb2_queue_init(q); | |
| 393 | + if (err) | |
| 394 | + return err; | |
| 395 | + vfd->queue = q; | |
| 396 | + | |
| 620 | 397 | video_set_drvdata(vfd, dev); |
| 621 | 398 | |
| 622 | 399 | err = video_register_device(vfd, type, -1); |
| @@ -306,221 +306,6 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field · 305 unmodified lines | ||
| 306 | 306 | } |
| 307 | 307 | |
| 308 | 308 | /* simple bubble-sort algorithm with duplicate elimination */ |
| 309 | −static int sort_and_eliminate(u32* values, int* count) | |
| 310 | −{ | |
| 311 | − int low = 0, high = 0, top = 0; | |
| 312 | − int cur = 0, next = 0; | |
| 313 | − | |
| 314 | − /* sanity checks */ | |
| 315 | − if( (0 > *count) || (NULL == values) ) { | |
| 316 | − return -EINVAL; | |
| 317 | − } | |
| 318 | − | |
| 319 | − /* bubble sort the first @count items of the array @values */ | |
| 320 | − for( top = *count; top > 0; top--) { | |
| 321 | − for( low = 0, high = 1; high < top; low++, high++) { | |
| 322 | − if( values[low] > values[high] ) | |
| 323 | − swap(values[low], values[high]); | |
| 324 | − } | |
| 325 | − } | |
| 326 | − | |
| 327 | − /* remove duplicate items */ | |
| 328 | − for( cur = 0, next = 1; next < *count; next++) { | |
| 329 | − if( values[cur] != values[next]) | |
| 330 | − values[++cur] = values[next]; | |
| 331 | − } | |
| 332 | − | |
| 333 | − *count = cur + 1; | |
| 334 | − | |
| 335 | − return 0; | |
| 336 | −} | |
| 337 | − | |
| 338 | −static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct saa7146_fh *fh, | |
| 339 | − struct saa7146_video_dma *vdma2, u32* clip_format, u32* arbtr_ctrl, enum v4l2_field field) | |
| 340 | −{ | |
| 341 | − struct saa7146_vv *vv = dev->vv_data; | |
| 342 | − __le32 *clipping = vv->d_clipping.cpu_addr; | |
| 343 | − | |
| 344 | − int width = vv->ov.win.w.width; | |
| 345 | − int height = vv->ov.win.w.height; | |
| 346 | − int clipcount = vv->ov.nclips; | |
| 347 | − | |
| 348 | − u32 line_list[32]; | |
| 349 | − u32 pixel_list[32]; | |
| 350 | − int numdwords = 0; | |
| 351 | − | |
| 352 | − int i = 0, j = 0; | |
| 353 | − int cnt_line = 0, cnt_pixel = 0; | |
| 354 | − | |
| 355 | − int x[32], y[32], w[32], h[32]; | |
| 356 | − | |
| 357 | − /* clear out memory */ | |
| 358 | − memset(&line_list[0], 0x00, sizeof(u32)*32); | |
| 359 | − memset(&pixel_list[0], 0x00, sizeof(u32)*32); | |
| 360 | − memset(clipping, 0x00, SAA7146_CLIPPING_MEM); | |
| 361 | − | |
| 362 | − /* fill the line and pixel-lists */ | |
| 363 | − for(i = 0; i < clipcount; i++) { | |
| 364 | − int l = 0, r = 0, t = 0, b = 0; | |
| 365 | − | |
| 366 | − x[i] = vv->ov.clips[i].c.left; | |
| 367 | − y[i] = vv->ov.clips[i].c.top; | |
| 368 | − w[i] = vv->ov.clips[i].c.width; | |
| 369 | − h[i] = vv->ov.clips[i].c.height; | |
| 370 | − | |
| 371 | − if( w[i] < 0) { | |
| 372 | − x[i] += w[i]; w[i] = -w[i]; | |
| 373 | − } | |
| 374 | − if( h[i] < 0) { | |
| 375 | − y[i] += h[i]; h[i] = -h[i]; | |
| 376 | − } | |
| 377 | − if( x[i] < 0) { | |
| 378 | − w[i] += x[i]; x[i] = 0; | |
| 379 | − } | |
| 380 | − if( y[i] < 0) { | |
| 381 | − h[i] += y[i]; y[i] = 0; | |
| 382 | − } | |
| 383 | − if( 0 != vv->vflip ) { | |
| 384 | − y[i] = height - y[i] - h[i]; | |
| 385 | − } | |
| 386 | − | |
| 387 | − l = x[i]; | |
| 388 | − r = x[i]+w[i]; | |
| 389 | − t = y[i]; | |
| 390 | − b = y[i]+h[i]; | |
| 391 | − | |
| 392 | − /* insert left/right coordinates */ | |
| 393 | − pixel_list[ 2*i ] = min_t(int, l, width); | |
| 394 | − pixel_list[(2*i)+1] = min_t(int, r, width); | |
| 395 | − /* insert top/bottom coordinates */ | |
| 396 | − line_list[ 2*i ] = min_t(int, t, height); | |
| 397 | − line_list[(2*i)+1] = min_t(int, b, height); | |
| 398 | − } | |
| 399 | − | |
| 400 | − /* sort and eliminate lists */ | |
| 401 | − cnt_line = cnt_pixel = 2*clipcount; | |
| 402 | − sort_and_eliminate( &pixel_list[0], &cnt_pixel ); | |
| 403 | − sort_and_eliminate( &line_list[0], &cnt_line ); | |
| 404 | − | |
| 405 | − /* calculate the number of used u32s */ | |
| 406 | − numdwords = max_t(int, (cnt_line+1), (cnt_pixel+1))*2; | |
| 407 | − numdwords = max_t(int, 4, numdwords); | |
| 408 | − numdwords = min_t(int, 64, numdwords); | |
| 409 | − | |
| 410 | − /* fill up cliptable */ | |
| 411 | − for(i = 0; i < cnt_pixel; i++) { | |
| 412 | − clipping[2*i] |= cpu_to_le32(pixel_list[i] << 16); | |
| 413 | − } | |
| 414 | − for(i = 0; i < cnt_line; i++) { | |
| 415 | − clipping[(2*i)+1] |= cpu_to_le32(line_list[i] << 16); | |
| 416 | − } | |
| 417 | − | |
| 418 | − /* fill up cliptable with the display infos */ | |
| 419 | − for(j = 0; j < clipcount; j++) { | |
| 420 | − | |
| 421 | − for(i = 0; i < cnt_pixel; i++) { | |
| 422 | − | |
| 423 | − if( x[j] < 0) | |
| 424 | − x[j] = 0; | |
| 425 | − | |
| 426 | − if( pixel_list[i] < (x[j] + w[j])) { | |
| 427 | − | |
| 428 | − if ( pixel_list[i] >= x[j] ) { | |
| 429 | − clipping[2*i] |= cpu_to_le32(1 << j); | |
| 430 | − } | |
| 431 | − } | |
| 432 | − } | |
| 433 | − for(i = 0; i < cnt_line; i++) { | |
| 434 | − | |
| 435 | − if( y[j] < 0) | |
| 436 | − y[j] = 0; | |
| 437 | − | |
| 438 | − if( line_list[i] < (y[j] + h[j]) ) { | |
| 439 | − | |
| 440 | − if( line_list[i] >= y[j] ) { | |
| 441 | − clipping[(2*i)+1] |= cpu_to_le32(1 << j); | |
| 442 | − } | |
| 443 | − } | |
| 444 | − } | |
| 445 | − } | |
| 446 | − | |
| 447 | − /* adjust arbitration control register */ | |
| 448 | − *arbtr_ctrl &= 0xffff00ff; | |
| 449 | − *arbtr_ctrl |= 0x00001c00; | |
| 450 | − | |
| 451 | − vdma2->base_even = vv->d_clipping.dma_handle; | |
| 452 | − vdma2->base_odd = vv->d_clipping.dma_handle; | |
| 453 | − vdma2->prot_addr = vv->d_clipping.dma_handle+((sizeof(u32))*(numdwords)); | |
| 454 | − vdma2->base_page = 0x04; | |
| 455 | − vdma2->pitch = 0x00; | |
| 456 | − vdma2->num_line_byte = (0 << 16 | (sizeof(u32))*(numdwords-1) ); | |
| 457 | − | |
| 458 | − /* set clipping-mode. this depends on the field(s) used */ | |
| 459 | − *clip_format &= 0xfffffff7; | |
| 460 | − if (V4L2_FIELD_HAS_BOTH(field)) { | |
| 461 | − *clip_format |= 0x00000008; | |
| 462 | − } else { | |
| 463 | − *clip_format |= 0x00000000; | |
| 464 | − } | |
| 465 | −} | |
| 466 | − | |
| 467 | −/* disable clipping */ | |
| 468 | −static void saa7146_disable_clipping(struct saa7146_dev *dev) | |
| 469 | −{ | |
| 470 | − u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); | |
| 471 | − | |
| 472 | − /* mask out relevant bits (=lower word)*/ | |
| 473 | − clip_format &= MASK_W1; | |
| 474 | − | |
| 475 | − /* upload clipping-registers*/ | |
| 476 | − saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); | |
| 477 | − saa7146_write(dev, MC2, (MASK_05 | MASK_21)); | |
| 478 | − | |
| 479 | − /* disable video dma2 */ | |
| 480 | − saa7146_write(dev, MC1, MASK_21); | |
| 481 | −} | |
| 482 | − | |
| 483 | −static void saa7146_set_clipping_rect(struct saa7146_fh *fh) | |
| 484 | −{ | |
| 485 | − struct saa7146_dev *dev = fh->dev; | |
| 486 | − struct saa7146_vv *vv = dev->vv_data; | |
| 487 | − enum v4l2_field field = vv->ov.win.field; | |
| 488 | − struct saa7146_video_dma vdma2; | |
| 489 | − u32 clip_format; | |
| 490 | − u32 arbtr_ctrl; | |
| 491 | − | |
| 492 | − /* check clipcount, disable clipping if clipcount == 0*/ | |
| 493 | − if (vv->ov.nclips == 0) { | |
| 494 | − saa7146_disable_clipping(dev); | |
| 495 | − return; | |
| 496 | − } | |
| 497 | − | |
| 498 | − clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); | |
| 499 | − arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); | |
| 500 | − | |
| 501 | − calculate_clipping_registers_rect(dev, fh, &vdma2, &clip_format, &arbtr_ctrl, field); | |
| 502 | − | |
| 503 | − /* set clipping format */ | |
| 504 | − clip_format &= 0xffff0008; | |
| 505 | − clip_format |= (SAA7146_CLIPPING_RECT << 4); | |
| 506 | − | |
| 507 | − /* prepare video dma2 */ | |
| 508 | − saa7146_write(dev, BASE_EVEN2, vdma2.base_even); | |
| 509 | − saa7146_write(dev, BASE_ODD2, vdma2.base_odd); | |
| 510 | − saa7146_write(dev, PROT_ADDR2, vdma2.prot_addr); | |
| 511 | − saa7146_write(dev, BASE_PAGE2, vdma2.base_page); | |
| 512 | − saa7146_write(dev, PITCH2, vdma2.pitch); | |
| 513 | − saa7146_write(dev, NUM_LINE_BYTE2, vdma2.num_line_byte); | |
| 514 | − | |
| 515 | − /* prepare the rest */ | |
| 516 | − saa7146_write(dev, CLIP_FORMAT_CTRL,clip_format); | |
| 517 | − saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); | |
| 518 | − | |
| 519 | − /* upload clip_control-register, clipping-registers, enable video dma2 */ | |
| 520 | − saa7146_write(dev, MC2, (MASK_05 | MASK_21 | MASK_03 | MASK_19)); | |
| 521 | − saa7146_write(dev, MC1, (MASK_05 | MASK_21)); | |
| 522 | −} | |
| 523 | − | |
| 524 | 309 | static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, enum v4l2_field field) |
| 525 | 310 | { |
| 526 | 311 | struct saa7146_vv *vv = dev->vv_data; |
| @@ -556,62 +341,6 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e · 29 unmodified lines | ||
| 556 | 341 | saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) ); |
| 557 | 342 | } |
| 558 | 343 | |
| 559 | −/* calculate the new memory offsets for a desired position */ | |
| 560 | −static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat) | |
| 561 | −{ | |
| 562 | − struct saa7146_vv *vv = dev->vv_data; | |
| 563 | − struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat); | |
| 564 | − | |
| 565 | − int b_depth = vv->ov_fmt->depth; | |
| 566 | − int b_bpl = vv->ov_fb.fmt.bytesperline; | |
| 567 | − /* The unsigned long cast is to remove a 64-bit compile warning since | |
| 568 | − it looks like a 64-bit address is cast to a 32-bit value, even | |
| 569 | − though the base pointer is really a 32-bit physical address that | |
| 570 | − goes into a 32-bit DMA register. | |
| 571 | − FIXME: might not work on some 64-bit platforms, but see the FIXME | |
| 572 | − in struct v4l2_framebuffer (videodev2.h) for that. | |
| 573 | − */ | |
| 574 | − u32 base = (u32)(unsigned long)vv->ov_fb.base; | |
| 575 | − | |
| 576 | − struct saa7146_video_dma vdma1; | |
| 577 | − | |
| 578 | − /* calculate memory offsets for picture, look if we shall top-down-flip */ | |
| 579 | − vdma1.pitch = 2*b_bpl; | |
| 580 | − if ( 0 == vv->vflip ) { | |
| 581 | − vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); | |
| 582 | − vdma1.base_odd = vdma1.base_even + (vdma1.pitch / 2); | |
| 583 | − vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2)); | |
| 584 | − } | |
| 585 | − else { | |
| 586 | − vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8)); | |
| 587 | − vdma1.base_odd = vdma1.base_even - (vdma1.pitch / 2); | |
| 588 | − vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2)); | |
| 589 | − } | |
| 590 | − | |
| 591 | − if (V4L2_FIELD_HAS_BOTH(field)) { | |
| 592 | − } else if (field == V4L2_FIELD_ALTERNATE) { | |
| 593 | − /* fixme */ | |
| 594 | − vdma1.base_odd = vdma1.prot_addr; | |
| 595 | − vdma1.pitch /= 2; | |
| 596 | − } else if (field == V4L2_FIELD_TOP) { | |
| 597 | − vdma1.base_odd = vdma1.prot_addr; | |
| 598 | − vdma1.pitch /= 2; | |
| 599 | − } else if (field == V4L2_FIELD_BOTTOM) { | |
| 600 | − vdma1.base_odd = vdma1.base_even; | |
| 601 | − vdma1.base_even = vdma1.prot_addr; | |
| 602 | − vdma1.pitch /= 2; | |
| 603 | − } | |
| 604 | − | |
| 605 | − if ( 0 != vv->vflip ) { | |
| 606 | − vdma1.pitch *= -1; | |
| 607 | − } | |
| 608 | − | |
| 609 | − vdma1.base_page = sfmt->swap; | |
| 610 | − vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels; | |
| 611 | − | |
| 612 | − saa7146_write_out_dma(dev, 1, &vdma1); | |
| 613 | −} | |
| 614 | − | |
| 615 | 344 | static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette) |
| 616 | 345 | { |
| 617 | 346 | u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); |
| @@ -645,30 +374,6 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy · 27 unmodified lines | ||
| 645 | 374 | } |
| 646 | 375 | EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync); |
| 647 | 376 | |
| 648 | −int saa7146_enable_overlay(struct saa7146_fh *fh) | |
| 649 | −{ | |
| 650 | − struct saa7146_dev *dev = fh->dev; | |
| 651 | − struct saa7146_vv *vv = dev->vv_data; | |
| 652 | − | |
| 653 | − saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field); | |
| 654 | − saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat); | |
| 655 | − saa7146_set_output_format(dev, vv->ov_fmt->trans); | |
| 656 | − saa7146_set_clipping_rect(fh); | |
| 657 | − | |
| 658 | − /* enable video dma1 */ | |
| 659 | − saa7146_write(dev, MC1, (MASK_06 | MASK_22)); | |
| 660 | − return 0; | |
| 661 | −} | |
| 662 | − | |
| 663 | −void saa7146_disable_overlay(struct saa7146_fh *fh) | |
| 664 | −{ | |
| 665 | − struct saa7146_dev *dev = fh->dev; | |
| 666 | − | |
| 667 | − /* disable clipping + video dma1 */ | |
| 668 | − saa7146_disable_clipping(dev); | |
| 669 | − saa7146_write(dev, MC1, MASK_22); | |
| 670 | −} | |
| 671 | − | |
| 672 | 377 | void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma) |
| 673 | 378 | { |
| 674 | 379 | int where = 0; |
| @@ -702,14 +407,14 @@ void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_vi · 27 unmodified lines | ||
| 702 | 407 | static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf) |
| 703 | 408 | { |
| 704 | 409 | struct saa7146_vv *vv = dev->vv_data; |
| 410 | + struct v4l2_pix_format *pix = &vv->video_fmt; | |
| 705 | 411 | struct saa7146_video_dma vdma1; |
| 412 | + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat); | |
| 706 | 413 | |
| 707 | − struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | |
| 708 | − | |
| 709 | − int width = buf->fmt->width; | |
| 710 | − int height = buf->fmt->height; | |
| 711 | − int bytesperline = buf->fmt->bytesperline; | |
| 712 | − enum v4l2_field field = buf->fmt->field; | |
| 414 | + int width = pix->width; | |
| 415 | + int height = pix->height; | |
| 416 | + int bytesperline = pix->bytesperline; | |
| 417 | + enum v4l2_field field = pix->field; | |
| 713 | 418 | |
| 714 | 419 | int depth = sfmt->depth; |
| 715 | 420 | |
| @@ -764,8 +469,9 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71 · 48 unmodified lines | ||
| 764 | 469 | |
| 765 | 470 | static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) |
| 766 | 471 | { |
| 767 | − int height = buf->fmt->height; | |
| 768 | − int width = buf->fmt->width; | |
| 472 | + struct v4l2_pix_format *pix = &vv->video_fmt; | |
| 473 | + int height = pix->height; | |
| 474 | + int width = pix->width; | |
| 769 | 475 | |
| 770 | 476 | vdma2->pitch = width; |
| 771 | 477 | vdma3->pitch = width; |
| @@ -795,8 +501,9 @@ static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struc · 23 unmodified lines | ||
| 795 | 501 | |
| 796 | 502 | static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) |
| 797 | 503 | { |
| 798 | − int height = buf->fmt->height; | |
| 799 | − int width = buf->fmt->width; | |
| 504 | + struct v4l2_pix_format *pix = &vv->video_fmt; | |
| 505 | + int height = pix->height; | |
| 506 | + int width = pix->width; | |
| 800 | 507 | |
| 801 | 508 | vdma2->pitch = width/2; |
| 802 | 509 | vdma3->pitch = width/2; |
| @@ -825,19 +532,20 @@ static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struc · 22 unmodified lines | ||
| 825 | 532 | static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf) |
| 826 | 533 | { |
| 827 | 534 | struct saa7146_vv *vv = dev->vv_data; |
| 535 | + struct v4l2_pix_format *pix = &vv->video_fmt; | |
| 828 | 536 | struct saa7146_video_dma vdma1; |
| 829 | 537 | struct saa7146_video_dma vdma2; |
| 830 | 538 | struct saa7146_video_dma vdma3; |
| 539 | + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat); | |
| 831 | 540 | |
| 832 | − struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | |
| 541 | + int width = pix->width; | |
| 542 | + int height = pix->height; | |
| 543 | + enum v4l2_field field = pix->field; | |
| 833 | 544 | |
| 834 | − int width = buf->fmt->width; | |
| 835 | − int height = buf->fmt->height; | |
| 836 | − enum v4l2_field field = buf->fmt->field; | |
| 837 | − | |
| 838 | − BUG_ON(0 == buf->pt[0].dma); | |
| 839 | − BUG_ON(0 == buf->pt[1].dma); | |
| 840 | − BUG_ON(0 == buf->pt[2].dma); | |
| 545 | + if (WARN_ON(!buf->pt[0].dma) || | |
| 546 | + WARN_ON(!buf->pt[1].dma) || | |
| 547 | + WARN_ON(!buf->pt[2].dma)) | |
| 548 | + return -1; | |
| 841 | 549 | |
| 842 | 550 | DEB_CAP("[size=%dx%d,fields=%s]\n", |
| 843 | 551 | width, height, v4l2_field_names[field]); |
| @@ -994,10 +702,27 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar) · 150 unmodified lines | ||
| 994 | 702 | WRITE_RPS0(CMD_STOP); |
| 995 | 703 | } |
| 996 | 704 | |
| 705 | +/* disable clipping */ | |
| 706 | +static void saa7146_disable_clipping(struct saa7146_dev *dev) | |
| 707 | +{ | |
| 708 | + u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL); | |
| 709 | + | |
| 710 | + /* mask out relevant bits (=lower word)*/ | |
| 711 | + clip_format &= MASK_W1; | |
| 712 | + | |
| 713 | + /* upload clipping-registers*/ | |
| 714 | + saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format); | |
| 715 | + saa7146_write(dev, MC2, (MASK_05 | MASK_21)); | |
| 716 | + | |
| 717 | + /* disable video dma2 */ | |
| 718 | + saa7146_write(dev, MC1, MASK_21); | |
| 719 | +} | |
| 720 | + | |
| 997 | 721 | void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) |
| 998 | 722 | { |
| 999 | − struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | |
| 1000 | 723 | struct saa7146_vv *vv = dev->vv_data; |
| 724 | + struct v4l2_pix_format *pix = &vv->video_fmt; | |
| 725 | + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat); | |
| 1001 | 726 | u32 vdma1_prot_addr; |
| 1002 | 727 | |
| 1003 | 728 | DEB_CAP("buf:%p, next:%p\n", buf, next); |
| @@ -1009,7 +734,7 @@ void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struc · 5 unmodified lines | ||
| 1009 | 734 | saa7146_write(dev, MC2, MASK_27 ); |
| 1010 | 735 | } |
| 1011 | 736 | |
| 1012 | − saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field); | |
| 737 | + saa7146_set_window(dev, pix->width, pix->height, pix->field); | |
| 1013 | 738 | saa7146_set_output_format(dev, sfmt->trans); |
| 1014 | 739 | saa7146_disable_clipping(dev); |
| 1015 | 740 | |
| @@ -207,7 +207,6 @@ static int buffer_activate(struct saa7146_dev *dev, · 206 unmodified lines | ||
| 207 | 207 | struct saa7146_buf *next) |
| 208 | 208 | { |
| 209 | 209 | struct saa7146_vv *vv = dev->vv_data; |
| 210 | − buf->vb.state = VIDEOBUF_ACTIVE; | |
| 211 | 210 | |
| 212 | 211 | DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next); |
| 213 | 212 | saa7146_set_vbi_capture(dev,buf,next); |
| @@ -216,114 +215,101 @@ static int buffer_activate(struct saa7146_dev *dev, · 2 unmodified lines | ||
| 216 | 215 | return 0; |
| 217 | 216 | } |
| 218 | 217 | |
| 219 | −static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field) | |
| 220 | −{ | |
| 221 | − struct file *file = q->priv_data; | |
| 222 | − struct saa7146_fh *fh = file->private_data; | |
| 223 | − struct saa7146_dev *dev = fh->dev; | |
| 224 | − struct saa7146_buf *buf = (struct saa7146_buf *)vb; | |
| 218 | +/* ------------------------------------------------------------------ */ | |
| 225 | 219 | |
| 226 | − int err = 0; | |
| 227 | − int lines, llength, size; | |
| 220 | +static int queue_setup(struct vb2_queue *q, | |
| 221 | + unsigned int *num_buffers, unsigned int *num_planes, | |
| 222 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 223 | +{ | |
| 224 | + unsigned int size = 16 * 2 * vbi_pixel_to_capture; | |
| 228 | 225 | |
| 229 | − lines = 16 * 2 ; /* 2 fields */ | |
| 230 | − llength = vbi_pixel_to_capture; | |
| 231 | − size = lines * llength; | |
| 226 | + if (*num_planes) | |
| 227 | + return sizes[0] < size ? -EINVAL : 0; | |
| 228 | + *num_planes = 1; | |
| 229 | + sizes[0] = size; | |
| 232 | 230 | |
| 233 | − DEB_VBI("vb:%p\n", vb); | |
| 231 | + return 0; | |
| 232 | +} | |
| 234 | 233 | |
| 235 | − if (0 != buf->vb.baddr && buf->vb.bsize < size) { | |
| 236 | − DEB_VBI("size mismatch\n"); | |
| 237 | − return -EINVAL; | |
| 238 | − } | |
| 234 | +static void buf_queue(struct vb2_buffer *vb) | |
| 235 | +{ | |
| 236 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 237 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 238 | + struct saa7146_dev *dev = vb2_get_drv_priv(vq); | |
| 239 | + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); | |
| 240 | + unsigned long flags; | |
| 239 | 241 | |
| 240 | − if (buf->vb.size != size) | |
| 241 | − saa7146_dma_free(dev,q,buf); | |
| 242 | + spin_lock_irqsave(&dev->slock, flags); | |
| 242 | 243 | |
| 243 | − if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | |
| 244 | − struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | |
| 244 | + saa7146_buffer_queue(dev, &dev->vv_data->vbi_dmaq, buf); | |
| 245 | + spin_unlock_irqrestore(&dev->slock, flags); | |
| 246 | +} | |
| 245 | 247 | |
| 246 | − buf->vb.width = llength; | |
| 247 | − buf->vb.height = lines; | |
| 248 | − buf->vb.size = size; | |
| 249 | − buf->vb.field = field; // FIXME: check this | |
| 248 | +static int buf_init(struct vb2_buffer *vb) | |
| 249 | +{ | |
| 250 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 251 | + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); | |
| 252 | + struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0); | |
| 253 | + struct scatterlist *list = sgt->sgl; | |
| 254 | + int length = sgt->nents; | |
| 255 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 256 | + struct saa7146_dev *dev = vb2_get_drv_priv(vq); | |
| 257 | + int ret; | |
| 250 | 258 | |
| 251 | − saa7146_pgtable_free(dev->pci, &buf->pt[2]); | |
| 252 | − saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); | |
| 253 | − | |
| 254 | − err = videobuf_iolock(q,&buf->vb, NULL); | |
| 255 | − if (err) | |
| 256 | − goto oops; | |
| 257 | − err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], | |
| 258 | − dma->sglist, dma->sglen); | |
| 259 | − if (0 != err) | |
| 260 | − return err; | |
| 261 | − } | |
| 262 | − buf->vb.state = VIDEOBUF_PREPARED; | |
| 263 | 259 | buf->activate = buffer_activate; |
| 264 | 260 | |
| 265 | − return 0; | |
| 266 | − | |
| 267 | − oops: | |
| 268 | − DEB_VBI("error out\n"); | |
| 269 | − saa7146_dma_free(dev,q,buf); | |
| 261 | + saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); | |
| 270 | 262 | |
| 271 | − return err; | |
| 263 | + ret = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], | |
| 264 | + list, length); | |
| 265 | + if (ret) | |
| 266 | + saa7146_pgtable_free(dev->pci, &buf->pt[2]); | |
| 267 | + return ret; | |
| 272 | 268 | } |
| 273 | 269 | |
| 274 | −static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | |
| 270 | +static int buf_prepare(struct vb2_buffer *vb) | |
| 275 | 271 | { |
| 276 | − int llength,lines; | |
| 277 | − | |
| 278 | − lines = 16 * 2 ; /* 2 fields */ | |
| 279 | − llength = vbi_pixel_to_capture; | |
| 280 | − | |
| 281 | − *size = lines * llength; | |
| 282 | − *count = 2; | |
| 283 | − | |
| 284 | − DEB_VBI("count:%d, size:%d\n", *count, *size); | |
| 272 | + unsigned int size = 16 * 2 * vbi_pixel_to_capture; | |
| 285 | 273 | |
| 274 | + if (vb2_plane_size(vb, 0) < size) | |
| 275 | + return -EINVAL; | |
| 276 | + vb2_set_plane_payload(vb, 0, size); | |
| 286 | 277 | return 0; |
| 287 | 278 | } |
| 288 | 279 | |
| 289 | −static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | |
| 280 | +static void buf_cleanup(struct vb2_buffer *vb) | |
| 290 | 281 | { |
| 291 | − struct file *file = q->priv_data; | |
| 292 | − struct saa7146_fh *fh = file->private_data; | |
| 293 | − struct saa7146_dev *dev = fh->dev; | |
| 294 | − struct saa7146_vv *vv = dev->vv_data; | |
| 295 | − struct saa7146_buf *buf = (struct saa7146_buf *)vb; | |
| 282 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 283 | + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); | |
| 284 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 285 | + struct saa7146_dev *dev = vb2_get_drv_priv(vq); | |
| 296 | 286 | |
| 297 | − DEB_VBI("vb:%p\n", vb); | |
| 298 | − saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf); | |
| 287 | + saa7146_pgtable_free(dev->pci, &buf->pt[2]); | |
| 299 | 288 | } |
| 300 | 289 | |
| 301 | −static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | |
| 290 | +static void return_buffers(struct vb2_queue *q, int state) | |
| 302 | 291 | { |
| 303 | − struct file *file = q->priv_data; | |
| 304 | − struct saa7146_fh *fh = file->private_data; | |
| 305 | − struct saa7146_dev *dev = fh->dev; | |
| 306 | − struct saa7146_buf *buf = (struct saa7146_buf *)vb; | |
| 307 | − | |
| 308 | − DEB_VBI("vb:%p\n", vb); | |
| 309 | − saa7146_dma_free(dev,q,buf); | |
| 292 | + struct saa7146_dev *dev = vb2_get_drv_priv(q); | |
| 293 | + struct saa7146_dmaqueue *dq = &dev->vv_data->vbi_dmaq; | |
| 294 | + struct saa7146_buf *buf; | |
| 295 | + | |
| 296 | + if (dq->curr) { | |
| 297 | + buf = dq->curr; | |
| 298 | + dq->curr = NULL; | |
| 299 | + vb2_buffer_done(&buf->vb.vb2_buf, state); | |
| 300 | + } | |
| 301 | + while (!list_empty(&dq->queue)) { | |
| 302 | + buf = list_entry(dq->queue.next, struct saa7146_buf, list); | |
| 303 | + list_del(&buf->list); | |
| 304 | + vb2_buffer_done(&buf->vb.vb2_buf, state); | |
| 305 | + } | |
| 310 | 306 | } |
| 311 | 307 | |
| 312 | −static const struct videobuf_queue_ops vbi_qops = { | |
| 313 | − .buf_setup = buffer_setup, | |
| 314 | − .buf_prepare = buffer_prepare, | |
| 315 | − .buf_queue = buffer_queue, | |
| 316 | − .buf_release = buffer_release, | |
| 317 | −}; | |
| 318 | − | |
| 319 | −/* ------------------------------------------------------------------ */ | |
| 320 | − | |
| 321 | −static void vbi_stop(struct saa7146_fh *fh, struct file *file) | |
| 308 | +static void vbi_stop(struct saa7146_dev *dev) | |
| 322 | 309 | { |
| 323 | − struct saa7146_dev *dev = fh->dev; | |
| 324 | 310 | struct saa7146_vv *vv = dev->vv_data; |
| 325 | 311 | unsigned long flags; |
| 326 | − DEB_VBI("dev:%p, fh:%p\n", dev, fh); | |
| 312 | + DEB_VBI("dev:%p\n", dev); | |
| 327 | 313 | |
| 328 | 314 | spin_lock_irqsave(&dev->slock,flags); |
| 329 | 315 | |
| @@ -336,13 +322,6 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) · 6 unmodified lines | ||
| 336 | 322 | /* shut down dma 3 transfers */ |
| 337 | 323 | saa7146_write(dev, MC1, MASK_20); |
| 338 | 324 | |
| 339 | − if (vv->vbi_dmaq.curr) | |
| 340 | − saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE); | |
| 341 | − | |
| 342 | − videobuf_queue_cancel(&fh->vbi_q); | |
| 343 | − | |
| 344 | − vv->vbi_streaming = NULL; | |
| 345 | − | |
| 346 | 325 | del_timer(&vv->vbi_dmaq.timeout); |
| 347 | 326 | del_timer(&vv->vbi_read_timeout); |
| 348 | 327 | |
| @@ -352,38 +331,22 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) · 3 unmodified lines | ||
| 352 | 331 | static void vbi_read_timeout(struct timer_list *t) |
| 353 | 332 | { |
| 354 | 333 | struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout); |
| 355 | − struct file *file = vv->vbi_read_timeout_file; | |
| 356 | − struct saa7146_fh *fh = file->private_data; | |
| 357 | − struct saa7146_dev *dev = fh->dev; | |
| 358 | − | |
| 359 | − DEB_VBI("dev:%p, fh:%p\n", dev, fh); | |
| 334 | + struct saa7146_dev *dev = vv->vbi_dmaq.dev; | |
| 360 | 335 | |
| 361 | − vbi_stop(fh, file); | |
| 362 | −} | |
| 363 | − | |
| 364 | −static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) | |
| 365 | −{ | |
| 366 | 336 | DEB_VBI("dev:%p\n", dev); |
| 367 | 337 | |
| 368 | − INIT_LIST_HEAD(&vv->vbi_dmaq.queue); | |
| 369 | − | |
| 370 | − timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0); | |
| 371 | − vv->vbi_dmaq.dev = dev; | |
| 372 | − | |
| 373 | − init_waitqueue_head(&vv->vbi_wq); | |
| 338 | + vbi_stop(dev); | |
| 374 | 339 | } |
| 375 | 340 | |
| 376 | −static int vbi_open(struct saa7146_dev *dev, struct file *file) | |
| 341 | +static int vbi_begin(struct saa7146_dev *dev) | |
| 377 | 342 | { |
| 378 | − struct saa7146_fh *fh = file->private_data; | |
| 379 | − struct saa7146_vv *vv = fh->dev->vv_data; | |
| 380 | − | |
| 343 | + struct saa7146_vv *vv = dev->vv_data; | |
| 381 | 344 | u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); |
| 382 | 345 | int ret = 0; |
| 383 | 346 | |
| 384 | − DEB_VBI("dev:%p, fh:%p\n", dev, fh); | |
| 347 | + DEB_VBI("dev:%p\n", dev); | |
| 385 | 348 | |
| 386 | − ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS); | |
| 349 | + ret = saa7146_res_get(dev, RESOURCE_DMA3_BRS); | |
| 387 | 350 | if (0 == ret) { |
| 388 | 351 | DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n"); |
| 389 | 352 | return -EBUSY; |
| @@ -395,15 +358,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) · 5 unmodified lines | ||
| 395 | 358 | saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); |
| 396 | 359 | saa7146_write(dev, MC2, (MASK_04|MASK_20)); |
| 397 | 360 | |
| 398 | − videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops, | |
| 399 | − &dev->pci->dev, &dev->slock, | |
| 400 | − V4L2_BUF_TYPE_VBI_CAPTURE, | |
| 401 | − V4L2_FIELD_SEQ_TB, // FIXME: does this really work? | |
| 402 | − sizeof(struct saa7146_buf), | |
| 403 | − file, &dev->v4l2_lock); | |
| 404 | − | |
| 405 | 361 | vv->vbi_read_timeout.function = vbi_read_timeout; |
| 406 | − vv->vbi_read_timeout_file = file; | |
| 407 | 362 | |
| 408 | 363 | /* initialize the brs */ |
| 409 | 364 | if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { |
| @@ -422,16 +377,52 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) · 12 unmodified lines | ||
| 422 | 377 | return 0; |
| 423 | 378 | } |
| 424 | 379 | |
| 425 | −static void vbi_close(struct saa7146_dev *dev, struct file *file) | |
| 380 | +static int start_streaming(struct vb2_queue *q, unsigned int count) | |
| 426 | 381 | { |
| 427 | − struct saa7146_fh *fh = file->private_data; | |
| 428 | − struct saa7146_vv *vv = dev->vv_data; | |
| 429 | − DEB_VBI("dev:%p, fh:%p\n", dev, fh); | |
| 382 | + struct saa7146_dev *dev = vb2_get_drv_priv(q); | |
| 383 | + int ret; | |
| 384 | + | |
| 385 | + if (!vb2_is_streaming(&dev->vv_data->vbi_dmaq.q)) | |
| 386 | + dev->vv_data->seqnr = 0; | |
| 387 | + ret = vbi_begin(dev); | |
| 388 | + if (ret) | |
| 389 | + return_buffers(q, VB2_BUF_STATE_QUEUED); | |
| 390 | + return ret; | |
| 391 | +} | |
| 430 | 392 | |
| 431 | − if( fh == vv->vbi_streaming ) { | |
| 432 | − vbi_stop(fh, file); | |
| 433 | − } | |
| 434 | − saa7146_res_free(fh, RESOURCE_DMA3_BRS); | |
| 393 | +static void stop_streaming(struct vb2_queue *q) | |
| 394 | +{ | |
| 395 | + struct saa7146_dev *dev = vb2_get_drv_priv(q); | |
| 396 | + | |
| 397 | + vbi_stop(dev); | |
| 398 | + return_buffers(q, VB2_BUF_STATE_ERROR); | |
| 399 | + saa7146_res_free(dev, RESOURCE_DMA3_BRS); | |
| 400 | +} | |
| 401 | + | |
| 402 | +const struct vb2_ops vbi_qops = { | |
| 403 | + .queue_setup = queue_setup, | |
| 404 | + .buf_queue = buf_queue, | |
| 405 | + .buf_init = buf_init, | |
| 406 | + .buf_prepare = buf_prepare, | |
| 407 | + .buf_cleanup = buf_cleanup, | |
| 408 | + .start_streaming = start_streaming, | |
| 409 | + .stop_streaming = stop_streaming, | |
| 410 | + .wait_prepare = vb2_ops_wait_prepare, | |
| 411 | + .wait_finish = vb2_ops_wait_finish, | |
| 412 | +}; | |
| 413 | + | |
| 414 | +/* ------------------------------------------------------------------ */ | |
| 415 | + | |
| 416 | +static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) | |
| 417 | +{ | |
| 418 | + DEB_VBI("dev:%p\n", dev); | |
| 419 | + | |
| 420 | + INIT_LIST_HEAD(&vv->vbi_dmaq.queue); | |
| 421 | + | |
| 422 | + timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0); | |
| 423 | + vv->vbi_dmaq.dev = dev; | |
| 424 | + | |
| 425 | + init_waitqueue_head(&vv->vbi_wq); | |
| 435 | 426 | } |
| 436 | 427 | |
| 437 | 428 | static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) |
| @@ -441,10 +432,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) · 3 unmodified lines | ||
| 441 | 432 | |
| 442 | 433 | if (vv->vbi_dmaq.curr) { |
| 443 | 434 | DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr); |
| 444 | − /* this must be += 2, one count for each field */ | |
| 445 | − vv->vbi_fieldcount+=2; | |
| 446 | − vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount; | |
| 447 | − saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE); | |
| 435 | + saa7146_buffer_finish(dev, &vv->vbi_dmaq, VB2_BUF_STATE_DONE); | |
| 448 | 436 | } else { |
| 449 | 437 | DEB_VBI("dev:%p\n", dev); |
| 450 | 438 | } |
| @@ -453,46 +441,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) · 2 unmodified lines | ||
| 453 | 441 | spin_unlock(&dev->slock); |
| 454 | 442 | } |
| 455 | 443 | |
| 456 | −static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | |
| 457 | −{ | |
| 458 | − struct saa7146_fh *fh = file->private_data; | |
| 459 | − struct saa7146_dev *dev = fh->dev; | |
| 460 | − struct saa7146_vv *vv = dev->vv_data; | |
| 461 | − ssize_t ret = 0; | |
| 462 | − | |
| 463 | − DEB_VBI("dev:%p, fh:%p\n", dev, fh); | |
| 464 | − | |
| 465 | − if( NULL == vv->vbi_streaming ) { | |
| 466 | − // fixme: check if dma3 is available | |
| 467 | − // fixme: activate vbi engine here if necessary. (really?) | |
| 468 | − vv->vbi_streaming = fh; | |
| 469 | − } | |
| 470 | − | |
| 471 | − if( fh != vv->vbi_streaming ) { | |
| 472 | − DEB_VBI("open %p is already using vbi capture\n", | |
| 473 | − vv->vbi_streaming); | |
| 474 | − return -EBUSY; | |
| 475 | − } | |
| 476 | − | |
| 477 | − mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT); | |
| 478 | − ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1, | |
| 479 | − file->f_flags & O_NONBLOCK); | |
| 480 | −/* | |
| 481 | − printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3)); | |
| 482 | − printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3)); | |
| 483 | − printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3)); | |
| 484 | − printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3)); | |
| 485 | − printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3)); | |
| 486 | − printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3)); | |
| 487 | − printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL)); | |
| 488 | −*/ | |
| 489 | − return ret; | |
| 490 | −} | |
| 491 | − | |
| 492 | 444 | const struct saa7146_use_ops saa7146_vbi_uops = { |
| 493 | 445 | .init = vbi_init, |
| 494 | − .open = vbi_open, | |
| 495 | − .release = vbi_close, | |
| 496 | 446 | .irq_done = vbi_irq_done, |
| 497 | − .read = vbi_read, | |
| 498 | 447 | }; |
| @@ -6,17 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <linux/module.h> |
| 7 | 7 | #include <linux/kernel.h> |
| 8 | 8 | |
| 9 | −static int max_memory = 32; | |
| 10 | − | |
| 11 | −module_param(max_memory, int, 0644); | |
| 12 | −MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)"); | |
| 13 | − | |
| 14 | −#define IS_CAPTURE_ACTIVE(fh) \ | |
| 15 | − (((vv->video_status & STATUS_CAPTURE) != 0) && (vv->video_fh == fh)) | |
| 16 | − | |
| 17 | −#define IS_OVERLAY_ACTIVE(fh) \ | |
| 18 | − (((vv->video_status & STATUS_OVERLAY) != 0) && (vv->video_fh == fh)) | |
| 19 | − | |
| 20 | 9 | /* format descriptions for capture and preview */ |
| 21 | 10 | static struct saa7146_format formats[] = { |
| 22 | 11 | { |
| @@ -54,7 +43,7 @@ static struct saa7146_format formats[] = { · 31 unmodified lines | ||
| 54 | 43 | .pixelformat = V4L2_PIX_FMT_YUV422P, |
| 55 | 44 | .trans = YUV422_DECOMPOSED, |
| 56 | 45 | .depth = 16, |
| 57 | − .flags = FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR, | |
| 46 | + .flags = FORMAT_IS_PLANAR, | |
| 58 | 47 | }, { |
| 59 | 48 | .pixelformat = V4L2_PIX_FMT_YVU420, |
| 60 | 49 | .trans = YUV420_DECOMPOSED, |
| @@ -91,115 +80,18 @@ struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fou · 30 unmodified lines | ||
| 91 | 80 | return NULL; |
| 92 | 81 | } |
| 93 | 82 | |
| 94 | −static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f); | |
| 95 | − | |
| 96 | −int saa7146_start_preview(struct saa7146_fh *fh) | |
| 97 | −{ | |
| 98 | − struct saa7146_dev *dev = fh->dev; | |
| 99 | − struct saa7146_vv *vv = dev->vv_data; | |
| 100 | − struct v4l2_format fmt; | |
| 101 | − int ret = 0, err = 0; | |
| 102 | − | |
| 103 | − DEB_EE("dev:%p, fh:%p\n", dev, fh); | |
| 104 | − | |
| 105 | − /* check if we have overlay information */ | |
| 106 | − if (vv->ov.fh == NULL) { | |
| 107 | − DEB_D("no overlay data available. try S_FMT first.\n"); | |
| 108 | − return -EAGAIN; | |
| 109 | − } | |
| 110 | − | |
| 111 | − /* check if streaming capture is running */ | |
| 112 | − if (IS_CAPTURE_ACTIVE(fh) != 0) { | |
| 113 | − DEB_D("streaming capture is active\n"); | |
| 114 | − return -EBUSY; | |
| 115 | − } | |
| 116 | − | |
| 117 | − /* check if overlay is running */ | |
| 118 | − if (IS_OVERLAY_ACTIVE(fh) != 0) { | |
| 119 | − if (vv->video_fh == fh) { | |
| 120 | − DEB_D("overlay is already active\n"); | |
| 121 | − return 0; | |
| 122 | − } | |
| 123 | − DEB_D("overlay is already active in another open\n"); | |
| 124 | − return -EBUSY; | |
| 125 | − } | |
| 126 | − | |
| 127 | − if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { | |
| 128 | − DEB_D("cannot get necessary overlay resources\n"); | |
| 129 | − return -EBUSY; | |
| 130 | − } | |
| 131 | − | |
| 132 | − fmt.fmt.win = vv->ov.win; | |
| 133 | − err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt); | |
| 134 | − if (0 != err) { | |
| 135 | − saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); | |
| 136 | − return -EBUSY; | |
| 137 | − } | |
| 138 | − vv->ov.win = fmt.fmt.win; | |
| 139 | − | |
| 140 | − DEB_D("%dx%d+%d+%d 0x%08x field=%s\n", | |
| 141 | − vv->ov.win.w.width, vv->ov.win.w.height, | |
| 142 | − vv->ov.win.w.left, vv->ov.win.w.top, | |
| 143 | − vv->ov_fmt->pixelformat, v4l2_field_names[vv->ov.win.field]); | |
| 144 | − | |
| 145 | − if (0 != (ret = saa7146_enable_overlay(fh))) { | |
| 146 | − DEB_D("enabling overlay failed: %d\n", ret); | |
| 147 | − saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); | |
| 148 | − return ret; | |
| 149 | − } | |
| 150 | − | |
| 151 | − vv->video_status = STATUS_OVERLAY; | |
| 152 | − vv->video_fh = fh; | |
| 153 | − | |
| 154 | − return 0; | |
| 155 | −} | |
| 156 | −EXPORT_SYMBOL_GPL(saa7146_start_preview); | |
| 157 | − | |
| 158 | −int saa7146_stop_preview(struct saa7146_fh *fh) | |
| 159 | −{ | |
| 160 | − struct saa7146_dev *dev = fh->dev; | |
| 161 | − struct saa7146_vv *vv = dev->vv_data; | |
| 162 | − | |
| 163 | − DEB_EE("dev:%p, fh:%p\n", dev, fh); | |
| 164 | − | |
| 165 | − /* check if streaming capture is running */ | |
| 166 | − if (IS_CAPTURE_ACTIVE(fh) != 0) { | |
| 167 | − DEB_D("streaming capture is active\n"); | |
| 168 | − return -EBUSY; | |
| 169 | − } | |
| 170 | − | |
| 171 | − /* check if overlay is running at all */ | |
| 172 | − if ((vv->video_status & STATUS_OVERLAY) == 0) { | |
| 173 | − DEB_D("no active overlay\n"); | |
| 174 | − return 0; | |
| 175 | − } | |
| 176 | − | |
| 177 | − if (vv->video_fh != fh) { | |
| 178 | − DEB_D("overlay is active, but in another open\n"); | |
| 179 | − return -EBUSY; | |
| 180 | − } | |
| 181 | − | |
| 182 | − vv->video_status = 0; | |
| 183 | − vv->video_fh = NULL; | |
| 184 | − | |
| 185 | − saa7146_disable_overlay(fh); | |
| 186 | − | |
| 187 | − saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); | |
| 188 | − | |
| 189 | − return 0; | |
| 190 | −} | |
| 191 | −EXPORT_SYMBOL_GPL(saa7146_stop_preview); | |
| 192 | − | |
| 193 | 83 | /********************************************************************************/ |
| 194 | 84 | /* common pagetable functions */ |
| 195 | 85 | |
| 196 | 86 | static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) |
| 197 | 87 | { |
| 88 | + struct saa7146_vv *vv = dev->vv_data; | |
| 198 | 89 | struct pci_dev *pci = dev->pci; |
| 199 | − struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); | |
| 200 | − struct scatterlist *list = dma->sglist; | |
| 201 | − int length = dma->sglen; | |
| 202 | − struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | |
| 90 | + struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0); | |
| 91 | + struct scatterlist *list = sgt->sgl; | |
| 92 | + int length = sgt->nents; | |
| 93 | + struct v4l2_pix_format *pix = &vv->video_fmt; | |
| 94 | + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat); | |
| 203 | 95 | |
| 204 | 96 | DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length); |
| 205 | 97 | |
| @@ -207,31 +99,32 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu · 1 unmodified line | ||
| 207 | 99 | struct saa7146_pgtable *pt1 = &buf->pt[0]; |
| 208 | 100 | struct saa7146_pgtable *pt2 = &buf->pt[1]; |
| 209 | 101 | struct saa7146_pgtable *pt3 = &buf->pt[2]; |
| 102 | + struct sg_dma_page_iter dma_iter; | |
| 210 | 103 | __le32 *ptr1, *ptr2, *ptr3; |
| 211 | 104 | __le32 fill; |
| 212 | 105 | |
| 213 | − int size = buf->fmt->width*buf->fmt->height; | |
| 214 | − int i,p,m1,m2,m3,o1,o2; | |
| 106 | + int size = pix->width * pix->height; | |
| 107 | + int i, m1, m2, m3, o1, o2; | |
| 215 | 108 | |
| 216 | 109 | switch( sfmt->depth ) { |
| 217 | 110 | case 12: { |
| 218 | 111 | /* create some offsets inside the page table */ |
| 219 | − m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; | |
| 220 | − m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1; | |
| 221 | − m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; | |
| 222 | − o1 = size%PAGE_SIZE; | |
| 223 | − o2 = (size+(size/4))%PAGE_SIZE; | |
| 112 | + m1 = ((size + PAGE_SIZE) / PAGE_SIZE) - 1; | |
| 113 | + m2 = ((size + (size / 4) + PAGE_SIZE) / PAGE_SIZE) - 1; | |
| 114 | + m3 = ((size + (size / 2) + PAGE_SIZE) / PAGE_SIZE) - 1; | |
| 115 | + o1 = size % PAGE_SIZE; | |
| 116 | + o2 = (size + (size / 4)) % PAGE_SIZE; | |
| 224 | 117 | DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n", |
| 225 | 118 | size, m1, m2, m3, o1, o2); |
| 226 | 119 | break; |
| 227 | 120 | } |
| 228 | 121 | case 16: { |
| 229 | 122 | /* create some offsets inside the page table */ |
| 230 | − m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; | |
| 231 | − m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; | |
| 232 | − m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; | |
| 233 | − o1 = size%PAGE_SIZE; | |
| 234 | − o2 = (size+(size/2))%PAGE_SIZE; | |
| 123 | + m1 = ((size + PAGE_SIZE) / PAGE_SIZE) - 1; | |
| 124 | + m2 = ((size + (size / 2) + PAGE_SIZE) / PAGE_SIZE) - 1; | |
| 125 | + m3 = ((2 * size + PAGE_SIZE) / PAGE_SIZE) - 1; | |
| 126 | + o1 = size % PAGE_SIZE; | |
| 127 | + o2 = (size + (size / 2)) % PAGE_SIZE; | |
| 235 | 128 | DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n", |
| 236 | 129 | size, m1, m2, m3, o1, o2); |
| 237 | 130 | break; |
| @@ -245,64 +138,37 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu · 7 unmodified lines | ||
| 245 | 138 | ptr2 = pt2->cpu; |
| 246 | 139 | ptr3 = pt3->cpu; |
| 247 | 140 | |
| 248 | − /* walk all pages, copy all page addresses to ptr1 */ | |
| 249 | − for (i = 0; i < length; i++, list++) { | |
| 250 | − for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr1++) | |
| 251 | − *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset); | |
| 252 | − } | |
| 253 | −/* | |
| 254 | − ptr1 = pt1->cpu; | |
| 255 | − for(j=0;j<40;j++) { | |
| 256 | − printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); | |
| 257 | − } | |
| 258 | −*/ | |
| 141 | + for_each_sg_dma_page(list, &dma_iter, length, 0) | |
| 142 | + *ptr1++ = cpu_to_le32(sg_page_iter_dma_address(&dma_iter) - list->offset); | |
| 259 | 143 | |
| 260 | 144 | /* if we have a user buffer, the first page may not be |
| 261 | 145 | aligned to a page boundary. */ |
| 262 | − pt1->offset = dma->sglist->offset; | |
| 263 | − pt2->offset = pt1->offset+o1; | |
| 264 | − pt3->offset = pt1->offset+o2; | |
| 146 | + pt1->offset = sgt->sgl->offset; | |
| 147 | + pt2->offset = pt1->offset + o1; | |
| 148 | + pt3->offset = pt1->offset + o2; | |
| 265 | 149 | |
| 266 | 150 | /* create video-dma2 page table */ |
| 267 | 151 | ptr1 = pt1->cpu; |
| 268 | − for(i = m1; i <= m2 ; i++, ptr2++) { | |
| 152 | + for (i = m1; i <= m2; i++, ptr2++) | |
| 269 | 153 | *ptr2 = ptr1[i]; |
| 270 | − } | |
| 271 | − fill = *(ptr2-1); | |
| 272 | − for(;i<1024;i++,ptr2++) { | |
| 154 | + fill = *(ptr2 - 1); | |
| 155 | + for (; i < 1024; i++, ptr2++) | |
| 273 | 156 | *ptr2 = fill; |
| 274 | − } | |
| 275 | 157 | /* create video-dma3 page table */ |
| 276 | 158 | ptr1 = pt1->cpu; |
| 277 | − for(i = m2; i <= m3; i++,ptr3++) { | |
| 159 | + for (i = m2; i <= m3; i++, ptr3++) | |
| 278 | 160 | *ptr3 = ptr1[i]; |
| 279 | − } | |
| 280 | − fill = *(ptr3-1); | |
| 281 | − for(;i<1024;i++,ptr3++) { | |
| 161 | + fill = *(ptr3 - 1); | |
| 162 | + for (; i < 1024; i++, ptr3++) | |
| 282 | 163 | *ptr3 = fill; |
| 283 | − } | |
| 284 | 164 | /* finally: finish up video-dma1 page table */ |
| 285 | − ptr1 = pt1->cpu+m1; | |
| 165 | + ptr1 = pt1->cpu + m1; | |
| 286 | 166 | fill = pt1->cpu[m1]; |
| 287 | − for(i=m1;i<1024;i++,ptr1++) { | |
| 167 | + for (i = m1; i < 1024; i++, ptr1++) | |
| 288 | 168 | *ptr1 = fill; |
| 289 | − } | |
| 290 | −/* | |
| 291 | − ptr1 = pt1->cpu; | |
| 292 | − ptr2 = pt2->cpu; | |
| 293 | − ptr3 = pt3->cpu; | |
| 294 | − for(j=0;j<40;j++) { | |
| 295 | − printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); | |
| 296 | − } | |
| 297 | − for(j=0;j<40;j++) { | |
| 298 | − printk("ptr2 %d: 0x%08x\n",j,ptr2[j]); | |
| 299 | − } | |
| 300 | − for(j=0;j<40;j++) { | |
| 301 | − printk("ptr3 %d: 0x%08x\n",j,ptr3[j]); | |
| 302 | − } | |
| 303 | −*/ | |
| 304 | 169 | } else { |
| 305 | 170 | struct saa7146_pgtable *pt = &buf->pt[0]; |
| 171 | + | |
| 306 | 172 | return saa7146_pgtable_build_single(pci, pt, list, length); |
| 307 | 173 | } |
| 308 | 174 | |
| @@ -313,34 +179,14 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu · 4 unmodified lines | ||
| 313 | 179 | /********************************************************************************/ |
| 314 | 180 | /* file operations */ |
| 315 | 181 | |
| 316 | −static int video_begin(struct saa7146_fh *fh) | |
| 182 | +static int video_begin(struct saa7146_dev *dev) | |
| 317 | 183 | { |
| 318 | − struct saa7146_dev *dev = fh->dev; | |
| 319 | 184 | struct saa7146_vv *vv = dev->vv_data; |
| 320 | 185 | struct saa7146_format *fmt = NULL; |
| 321 | 186 | unsigned int resource; |
| 322 | − int ret = 0, err = 0; | |
| 323 | − | |
| 324 | − DEB_EE("dev:%p, fh:%p\n", dev, fh); | |
| 325 | − | |
| 326 | − if ((vv->video_status & STATUS_CAPTURE) != 0) { | |
| 327 | − if (vv->video_fh == fh) { | |
| 328 | − DEB_S("already capturing\n"); | |
| 329 | − return 0; | |
| 330 | − } | |
| 331 | − DEB_S("already capturing in another open\n"); | |
| 332 | − return -EBUSY; | |
| 333 | − } | |
| 187 | + int ret = 0; | |
| 334 | 188 | |
| 335 | − if ((vv->video_status & STATUS_OVERLAY) != 0) { | |
| 336 | − DEB_S("warning: suspending overlay video for streaming capture\n"); | |
| 337 | − vv->ov_suspend = vv->video_fh; | |
| 338 | − err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ | |
| 339 | − if (0 != err) { | |
| 340 | − DEB_D("suspending video failed. aborting\n"); | |
| 341 | − return err; | |
| 342 | − } | |
| 343 | − } | |
| 189 | + DEB_EE("dev:%p\n", dev); | |
| 344 | 190 | |
| 345 | 191 | fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat); |
| 346 | 192 | /* we need to have a valid format set here */ |
| @@ -353,13 +199,9 @@ static int video_begin(struct saa7146_fh *fh) · 6 unmodified lines | ||
| 353 | 199 | resource = RESOURCE_DMA1_HPS; |
| 354 | 200 | } |
| 355 | 201 | |
| 356 | − ret = saa7146_res_get(fh, resource); | |
| 202 | + ret = saa7146_res_get(dev, resource); | |
| 357 | 203 | if (0 == ret) { |
| 358 | 204 | DEB_S("cannot get capture resource %d\n", resource); |
| 359 | − if (vv->ov_suspend != NULL) { | |
| 360 | − saa7146_start_preview(vv->ov_suspend); | |
| 361 | − vv->ov_suspend = NULL; | |
| 362 | − } | |
| 363 | 205 | return -EBUSY; |
| 364 | 206 | } |
| 365 | 207 | |
| @@ -369,37 +211,22 @@ static int video_begin(struct saa7146_fh *fh) · 3 unmodified lines | ||
| 369 | 211 | /* enable rps0 irqs */ |
| 370 | 212 | SAA7146_IER_ENABLE(dev, MASK_27); |
| 371 | 213 | |
| 372 | − vv->video_fh = fh; | |
| 373 | − vv->video_status = STATUS_CAPTURE; | |
| 374 | − | |
| 375 | 214 | return 0; |
| 376 | 215 | } |
| 377 | 216 | |
| 378 | −static int video_end(struct saa7146_fh *fh, struct file *file) | |
| 217 | +static void video_end(struct saa7146_dev *dev) | |
| 379 | 218 | { |
| 380 | − struct saa7146_dev *dev = fh->dev; | |
| 381 | 219 | struct saa7146_vv *vv = dev->vv_data; |
| 382 | − struct saa7146_dmaqueue *q = &vv->video_dmaq; | |
| 383 | 220 | struct saa7146_format *fmt = NULL; |
| 384 | 221 | unsigned long flags; |
| 385 | 222 | unsigned int resource; |
| 386 | 223 | u32 dmas = 0; |
| 387 | − DEB_EE("dev:%p, fh:%p\n", dev, fh); | |
| 388 | − | |
| 389 | − if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { | |
| 390 | − DEB_S("not capturing\n"); | |
| 391 | − return 0; | |
| 392 | − } | |
| 393 | − | |
| 394 | − if (vv->video_fh != fh) { | |
| 395 | − DEB_S("capturing, but in another open\n"); | |
| 396 | − return -EBUSY; | |
| 397 | − } | |
| 224 | + DEB_EE("dev:%p\n", dev); | |
| 398 | 225 | |
| 399 | 226 | fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat); |
| 400 | 227 | /* we need to have a valid format set here */ |
| 401 | 228 | if (!fmt) |
| 402 | − return -EINVAL; | |
| 229 | + return; | |
| 403 | 230 | |
| 404 | 231 | if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { |
| 405 | 232 | resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; |
| @@ -419,88 +246,24 @@ static int video_end(struct saa7146_fh *fh, struct file *file) · 13 unmodified lines | ||
| 419 | 246 | /* shut down all used video dma transfers */ |
| 420 | 247 | saa7146_write(dev, MC1, dmas); |
| 421 | 248 | |
| 422 | − if (q->curr) | |
| 423 | − saa7146_buffer_finish(dev, q, VIDEOBUF_DONE); | |
| 424 | − | |
| 425 | 249 | spin_unlock_irqrestore(&dev->slock, flags); |
| 426 | 250 | |
| 427 | − vv->video_fh = NULL; | |
| 428 | − vv->video_status = 0; | |
| 429 | − | |
| 430 | − saa7146_res_free(fh, resource); | |
| 431 | − | |
| 432 | − if (vv->ov_suspend != NULL) { | |
| 433 | − saa7146_start_preview(vv->ov_suspend); | |
| 434 | − vv->ov_suspend = NULL; | |
| 435 | − } | |
| 436 | − | |
| 437 | − return 0; | |
| 251 | + saa7146_res_free(dev, resource); | |
| 438 | 252 | } |
| 439 | 253 | |
| 440 | 254 | static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) |
| 441 | 255 | { |
| 442 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 256 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 443 | 257 | |
| 444 | 258 | strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver)); |
| 445 | 259 | strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); |
| 446 | − cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | | |
| 260 | + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | |
| 447 | 261 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | |
| 448 | 262 | V4L2_CAP_DEVICE_CAPS; |
| 449 | 263 | cap->capabilities |= dev->ext_vv_data->capabilities; |
| 450 | 264 | return 0; |
| 451 | 265 | } |
| 452 | 266 | |
| 453 | −static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) | |
| 454 | −{ | |
| 455 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 456 | − struct saa7146_vv *vv = dev->vv_data; | |
| 457 | − | |
| 458 | − *fb = vv->ov_fb; | |
| 459 | − fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | |
| 460 | − fb->flags = V4L2_FBUF_FLAG_PRIMARY; | |
| 461 | − return 0; | |
| 462 | −} | |
| 463 | − | |
| 464 | −static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb) | |
| 465 | −{ | |
| 466 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 467 | − struct saa7146_vv *vv = dev->vv_data; | |
| 468 | − struct saa7146_format *fmt; | |
| 469 | − | |
| 470 | − DEB_EE("VIDIOC_S_FBUF\n"); | |
| 471 | − | |
| 472 | − if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) | |
| 473 | − return -EPERM; | |
| 474 | − | |
| 475 | − /* check args */ | |
| 476 | − fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat); | |
| 477 | − if (NULL == fmt) | |
| 478 | − return -EINVAL; | |
| 479 | − | |
| 480 | − /* planar formats are not allowed for overlay video, clipping and video dma would clash */ | |
| 481 | − if (fmt->flags & FORMAT_IS_PLANAR) | |
| 482 | − DEB_S("planar pixelformat '%4.4s' not allowed for overlay\n", | |
| 483 | − (char *)&fmt->pixelformat); | |
| 484 | − | |
| 485 | − /* check if overlay is running */ | |
| 486 | − if (IS_OVERLAY_ACTIVE(fh) != 0) { | |
| 487 | − if (vv->video_fh != fh) { | |
| 488 | − DEB_D("refusing to change framebuffer information while overlay is active in another open\n"); | |
| 489 | − return -EBUSY; | |
| 490 | − } | |
| 491 | − } | |
| 492 | − | |
| 493 | − /* ok, accept it */ | |
| 494 | − vv->ov_fb = *fb; | |
| 495 | − vv->ov_fmt = fmt; | |
| 496 | − | |
| 497 | − if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) { | |
| 498 | − vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8; | |
| 499 | − DEB_D("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline); | |
| 500 | − } | |
| 501 | − return 0; | |
| 502 | −} | |
| 503 | − | |
| 504 | 267 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) |
| 505 | 268 | { |
| 506 | 269 | if (f->index >= ARRAY_SIZE(formats)) |
| @@ -543,13 +306,13 @@ int saa7146_s_ctrl(struct v4l2_ctrl *ctrl) · 36 unmodified lines | ||
| 543 | 306 | |
| 544 | 307 | case V4L2_CID_HFLIP: |
| 545 | 308 | /* fixme: we can support changing VFLIP and HFLIP here... */ |
| 546 | − if ((vv->video_status & STATUS_CAPTURE)) | |
| 309 | + if (vb2_is_busy(&vv->video_dmaq.q)) | |
| 547 | 310 | return -EBUSY; |
| 548 | 311 | vv->hflip = ctrl->val; |
| 549 | 312 | break; |
| 550 | 313 | |
| 551 | 314 | case V4L2_CID_VFLIP: |
| 552 | − if ((vv->video_status & STATUS_CAPTURE)) | |
| 315 | + if (vb2_is_busy(&vv->video_dmaq.q)) | |
| 553 | 316 | return -EBUSY; |
| 554 | 317 | vv->vflip = ctrl->val; |
| 555 | 318 | break; |
| @@ -557,20 +320,13 @@ int saa7146_s_ctrl(struct v4l2_ctrl *ctrl) · 1 unmodified line | ||
| 557 | 320 | default: |
| 558 | 321 | return -EINVAL; |
| 559 | 322 | } |
| 560 | − | |
| 561 | − if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */ | |
| 562 | − struct saa7146_fh *fh = vv->video_fh; | |
| 563 | − | |
| 564 | − saa7146_stop_preview(fh); | |
| 565 | − saa7146_start_preview(fh); | |
| 566 | − } | |
| 567 | 323 | return 0; |
| 568 | 324 | } |
| 569 | 325 | |
| 570 | 326 | static int vidioc_g_parm(struct file *file, void *fh, |
| 571 | 327 | struct v4l2_streamparm *parm) |
| 572 | 328 | { |
| 573 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 329 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 574 | 330 | struct saa7146_vv *vv = dev->vv_data; |
| 575 | 331 | |
| 576 | 332 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| @@ -583,25 +339,16 @@ static int vidioc_g_parm(struct file *file, void *fh, · 6 unmodified lines | ||
| 583 | 339 | |
| 584 | 340 | static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) |
| 585 | 341 | { |
| 586 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 342 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 587 | 343 | struct saa7146_vv *vv = dev->vv_data; |
| 588 | 344 | |
| 589 | 345 | f->fmt.pix = vv->video_fmt; |
| 590 | 346 | return 0; |
| 591 | 347 | } |
| 592 | 348 | |
| 593 | −static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) | |
| 594 | −{ | |
| 595 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 596 | − struct saa7146_vv *vv = dev->vv_data; | |
| 597 | − | |
| 598 | − f->fmt.win = vv->ov.win; | |
| 599 | − return 0; | |
| 600 | −} | |
| 601 | − | |
| 602 | 349 | static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f) |
| 603 | 350 | { |
| 604 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 351 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 605 | 352 | struct saa7146_vv *vv = dev->vv_data; |
| 606 | 353 | |
| 607 | 354 | f->fmt.vbi = vv->vbi_fmt; |
| @@ -610,7 +357,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format · 2 unmodified lines | ||
| 610 | 357 | |
| 611 | 358 | static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) |
| 612 | 359 | { |
| 613 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 360 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 614 | 361 | struct saa7146_vv *vv = dev->vv_data; |
| 615 | 362 | struct saa7146_format *fmt; |
| 616 | 363 | enum v4l2_field field; |
| @@ -634,24 +381,21 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma · 17 unmodified lines | ||
| 634 | 381 | } |
| 635 | 382 | switch (field) { |
| 636 | 383 | case V4L2_FIELD_ALTERNATE: |
| 637 | − vv->last_field = V4L2_FIELD_TOP; | |
| 638 | − maxh = maxh / 2; | |
| 639 | − break; | |
| 640 | 384 | case V4L2_FIELD_TOP: |
| 641 | 385 | case V4L2_FIELD_BOTTOM: |
| 642 | − vv->last_field = V4L2_FIELD_INTERLACED; | |
| 643 | 386 | maxh = maxh / 2; |
| 644 | 387 | break; |
| 645 | − case V4L2_FIELD_INTERLACED: | |
| 646 | − vv->last_field = V4L2_FIELD_INTERLACED; | |
| 647 | − break; | |
| 648 | 388 | default: |
| 649 | − DEB_D("no known field mode '%d'\n", field); | |
| 650 | − return -EINVAL; | |
| 389 | + field = V4L2_FIELD_INTERLACED; | |
| 390 | + break; | |
| 651 | 391 | } |
| 652 | 392 | |
| 653 | 393 | f->fmt.pix.field = field; |
| 654 | 394 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 395 | + if (f->fmt.pix.width < 48) | |
| 396 | + f->fmt.pix.width = 48; | |
| 397 | + if (f->fmt.pix.height < 32) | |
| 398 | + f->fmt.pix.height = 32; | |
| 655 | 399 | if (f->fmt.pix.width > maxw) |
| 656 | 400 | f->fmt.pix.width = maxw; |
| 657 | 401 | if (f->fmt.pix.height > maxh) |
| @@ -673,169 +417,65 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma · 15 unmodified lines | ||
| 673 | 417 | return 0; |
| 674 | 418 | } |
| 675 | 419 | |
| 676 | − | |
| 677 | −static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) | |
| 420 | +static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) | |
| 678 | 421 | { |
| 679 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 680 | − struct saa7146_vv *vv = dev->vv_data; | |
| 681 | − struct v4l2_window *win = &f->fmt.win; | |
| 682 | − enum v4l2_field field; | |
| 683 | − int maxw, maxh; | |
| 684 | − | |
| 685 | − DEB_EE("dev:%p\n", dev); | |
| 686 | − | |
| 687 | − if (NULL == vv->ov_fb.base) { | |
| 688 | − DEB_D("no fb base set\n"); | |
| 689 | − return -EINVAL; | |
| 690 | − } | |
| 691 | − if (NULL == vv->ov_fmt) { | |
| 692 | − DEB_D("no fb fmt set\n"); | |
| 693 | − return -EINVAL; | |
| 694 | − } | |
| 695 | − if (win->w.width < 48 || win->w.height < 32) { | |
| 696 | − DEB_D("min width/height. (%d,%d)\n", | |
| 697 | − win->w.width, win->w.height); | |
| 698 | − return -EINVAL; | |
| 699 | − } | |
| 700 | − if (win->clipcount > 16) { | |
| 701 | − DEB_D("clipcount too big\n"); | |
| 702 | − return -EINVAL; | |
| 703 | − } | |
| 704 | − | |
| 705 | − field = win->field; | |
| 706 | − maxw = vv->standard->h_max_out; | |
| 707 | − maxh = vv->standard->v_max_out; | |
| 708 | − | |
| 709 | − if (V4L2_FIELD_ANY == field) { | |
| 710 | − field = (win->w.height > maxh / 2) | |
| 711 | − ? V4L2_FIELD_INTERLACED | |
| 712 | − : V4L2_FIELD_TOP; | |
| 713 | − } | |
| 714 | − switch (field) { | |
| 715 | − case V4L2_FIELD_TOP: | |
| 716 | − case V4L2_FIELD_BOTTOM: | |
| 717 | − case V4L2_FIELD_ALTERNATE: | |
| 718 | − maxh = maxh / 2; | |
| 719 | − break; | |
| 720 | − case V4L2_FIELD_INTERLACED: | |
| 721 | − break; | |
| 722 | − default: | |
| 723 | − DEB_D("no known field mode '%d'\n", field); | |
| 724 | − return -EINVAL; | |
| 725 | − } | |
| 726 | − | |
| 727 | − win->field = field; | |
| 728 | − if (win->w.width > maxw) | |
| 729 | − win->w.width = maxw; | |
| 730 | − if (win->w.height > maxh) | |
| 731 | − win->w.height = maxh; | |
| 732 | − | |
| 733 | − return 0; | |
| 734 | −} | |
| 735 | − | |
| 736 | −static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f) | |
| 737 | −{ | |
| 738 | − struct saa7146_fh *fh = __fh; | |
| 739 | − struct saa7146_dev *dev = fh->dev; | |
| 422 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 740 | 423 | struct saa7146_vv *vv = dev->vv_data; |
| 741 | 424 | int err; |
| 742 | 425 | |
| 743 | − DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh); | |
| 744 | − if (IS_CAPTURE_ACTIVE(fh) != 0) { | |
| 426 | + DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p\n", dev); | |
| 427 | + if (vb2_is_busy(&vv->video_dmaq.q)) { | |
| 745 | 428 | DEB_EE("streaming capture is active\n"); |
| 746 | 429 | return -EBUSY; |
| 747 | 430 | } |
| 748 | 431 | err = vidioc_try_fmt_vid_cap(file, fh, f); |
| 749 | 432 | if (0 != err) |
| 750 | 433 | return err; |
| 434 | + switch (f->fmt.pix.field) { | |
| 435 | + case V4L2_FIELD_ALTERNATE: | |
| 436 | + vv->last_field = V4L2_FIELD_TOP; | |
| 437 | + break; | |
| 438 | + default: | |
| 439 | + vv->last_field = V4L2_FIELD_INTERLACED; | |
| 440 | + break; | |
| 441 | + } | |
| 751 | 442 | vv->video_fmt = f->fmt.pix; |
| 752 | 443 | DEB_EE("set to pixelformat '%4.4s'\n", |
| 753 | 444 | (char *)&vv->video_fmt.pixelformat); |
| 754 | 445 | return 0; |
| 755 | 446 | } |
| 756 | 447 | |
| 757 | −static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f) | |
| 758 | −{ | |
| 759 | − struct saa7146_fh *fh = __fh; | |
| 760 | − struct saa7146_dev *dev = fh->dev; | |
| 761 | − struct saa7146_vv *vv = dev->vv_data; | |
| 762 | − int err; | |
| 763 | − | |
| 764 | − DEB_EE("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh); | |
| 765 | − err = vidioc_try_fmt_vid_overlay(file, fh, f); | |
| 766 | − if (0 != err) | |
| 767 | − return err; | |
| 768 | − vv->ov.win = f->fmt.win; | |
| 769 | − vv->ov.nclips = f->fmt.win.clipcount; | |
| 770 | − if (vv->ov.nclips > 16) | |
| 771 | − vv->ov.nclips = 16; | |
| 772 | − memcpy(vv->ov.clips, f->fmt.win.clips, | |
| 773 | − sizeof(struct v4l2_clip) * vv->ov.nclips); | |
| 774 | − | |
| 775 | − /* vv->ov.fh is used to indicate that we have valid overlay information, too */ | |
| 776 | − vv->ov.fh = fh; | |
| 777 | − | |
| 778 | − /* check if our current overlay is active */ | |
| 779 | − if (IS_OVERLAY_ACTIVE(fh) != 0) { | |
| 780 | − saa7146_stop_preview(fh); | |
| 781 | − saa7146_start_preview(fh); | |
| 782 | − } | |
| 783 | − return 0; | |
| 784 | −} | |
| 785 | − | |
| 786 | 448 | static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) |
| 787 | 449 | { |
| 788 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 450 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 789 | 451 | struct saa7146_vv *vv = dev->vv_data; |
| 790 | 452 | |
| 791 | 453 | *norm = vv->standard->id; |
| 792 | 454 | return 0; |
| 793 | 455 | } |
| 794 | 456 | |
| 795 | − /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) | |
| 796 | − PAL / NTSC / SECAM. if your hardware does not (or does more) | |
| 797 | − -- override this function in your extension */ | |
| 798 | −/* | |
| 799 | − case VIDIOC_ENUMSTD: | |
| 800 | − { | |
| 801 | − struct v4l2_standard *e = arg; | |
| 802 | − if (e->index < 0 ) | |
| 803 | − return -EINVAL; | |
| 804 | − if( e->index < dev->ext_vv_data->num_stds ) { | |
| 805 | − DEB_EE("VIDIOC_ENUMSTD: index:%d\n", e->index); | |
| 806 | − v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); | |
| 807 | − return 0; | |
| 808 | − } | |
| 809 | − return -EINVAL; | |
| 810 | − } | |
| 811 | − */ | |
| 812 | − | |
| 813 | 457 | static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) |
| 814 | 458 | { |
| 815 | − struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | |
| 459 | + struct saa7146_dev *dev = video_drvdata(file); | |
| 816 | 460 | struct saa7146_vv *vv = dev->vv_data; |
| 817 | 461 | int found = 0; |
| 818 | − int err, i; | |
| 462 | + int i; | |
| 819 | 463 | |
| 820 | 464 | DEB_EE("VIDIOC_S_STD\n"); |
| 821 | 465 | |
| 822 | − if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { | |
| 466 | + for (i = 0; i < dev->ext_vv_data->num_stds; i++) | |
| 467 | + if (id & dev->ext_vv_data->stds[i].id) | |
| 468 | + break; | |
| 469 | + | |
| 470 | + if (i != dev->ext_vv_data->num_stds && | |
| 471 | + vv->standard == &dev->ext_vv_data->stds[i]) | |
| 472 | + return 0; | |
| 473 | + | |
| 474 | + if (vb2_is_busy(&vv->video_dmaq.q) || vb2_is_busy(&vv->vbi_dmaq.q)) { | |
| 823 | 475 | DEB_D("cannot change video standard while streaming capture is active\n"); |
| 824 | 476 | return -EBUSY; |
| 825 | 477 | } |
| 826 | 478 | |
| 827 | − if ((vv->video_status & STATUS_OVERLAY) != 0) { | |
| 828 | − vv->ov_suspend = vv->video_fh; | |
| 829 | − err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ | |
| 830 | − if (0 != err) { | |
| 831 | − DEB_D("suspending video failed. aborting\n"); | |
| 832 | − return err; | |
| 833 | − } | |
| 834 | − } | |
| 835 | − | |
| 836 | − for (i = 0; i < dev->ext_vv_data->num_stds; i++) | |
| 837 | − if (id & dev->ext_vv_data->stds[i].id) | |
| 838 | − break; | |
| 839 | 479 | if (i != dev->ext_vv_data->num_stds) { |
| 840 | 480 | vv->standard = &dev->ext_vv_data->stds[i]; |
| 841 | 481 | if (NULL != dev->ext_vv_data->std_callback) |
| @@ -843,11 +483,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) · 1 unmodified line | ||
| 843 | 483 | found = 1; |
| 844 | 484 | } |
| 845 | 485 | |
| 846 | − if (vv->ov_suspend != NULL) { | |
| 847 | − saa7146_start_preview(vv->ov_suspend); | |
| 848 | − vv->ov_suspend = NULL; | |
| 849 | − } | |
| 850 | − | |
| 851 | 486 | if (!found) { |
| 852 | 487 | DEB_EE("VIDIOC_S_STD: standard not found\n"); |
| 853 | 488 | return -EINVAL; |
| @@ -857,138 +492,22 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) · 3 unmodified lines | ||
| 857 | 492 | return 0; |
| 858 | 493 | } |
| 859 | 494 | |
| 860 | −static int vidioc_overlay(struct file *file, void *fh, unsigned int on) | |
| 861 | −{ | |
| 862 | − int err; | |
| 863 | − | |
| 864 | − DEB_D("VIDIOC_OVERLAY on:%d\n", on); | |
| 865 | − if (on) | |
| 866 | − err = saa7146_start_preview(fh); | |
| 867 | − else | |
| 868 | − err = saa7146_stop_preview(fh); | |
| 869 | − return err; | |
| 870 | −} | |
| 871 | − | |
| 872 | −static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b) | |
| 873 | −{ | |
| 874 | − struct saa7146_fh *fh = __fh; | |
| 875 | − | |
| 876 | − if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 877 | − return videobuf_reqbufs(&fh->video_q, b); | |
| 878 | − if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE) | |
| 879 | − return videobuf_reqbufs(&fh->vbi_q, b); | |
| 880 | − return -EINVAL; | |
| 881 | −} | |
| 882 | − | |
| 883 | −static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | |
| 884 | −{ | |
| 885 | − struct saa7146_fh *fh = __fh; | |
| 886 | − | |
| 887 | − if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 888 | − return videobuf_querybuf(&fh->video_q, buf); | |
| 889 | − if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) | |
| 890 | − return videobuf_querybuf(&fh->vbi_q, buf); | |
| 891 | − return -EINVAL; | |
| 892 | −} | |
| 893 | − | |
| 894 | −static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | |
| 895 | −{ | |
| 896 | − struct saa7146_fh *fh = __fh; | |
| 897 | − | |
| 898 | − if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 899 | − return videobuf_qbuf(&fh->video_q, buf); | |
| 900 | − if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) | |
| 901 | − return videobuf_qbuf(&fh->vbi_q, buf); | |
| 902 | − return -EINVAL; | |
| 903 | −} | |
| 904 | − | |
| 905 | −static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | |
| 906 | −{ | |
| 907 | − struct saa7146_fh *fh = __fh; | |
| 908 | − | |
| 909 | − if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 910 | − return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK); | |
| 911 | − if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) | |
| 912 | − return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK); | |
| 913 | − return -EINVAL; | |
| 914 | −} | |
| 915 | − | |
| 916 | −static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) | |
| 917 | −{ | |
| 918 | − struct saa7146_fh *fh = __fh; | |
| 919 | − int err; | |
| 920 | − | |
| 921 | − DEB_D("VIDIOC_STREAMON, type:%d\n", type); | |
| 922 | − | |
| 923 | − err = video_begin(fh); | |
| 924 | − if (err) | |
| 925 | − return err; | |
| 926 | − if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 927 | − return videobuf_streamon(&fh->video_q); | |
| 928 | − if (type == V4L2_BUF_TYPE_VBI_CAPTURE) | |
| 929 | − return videobuf_streamon(&fh->vbi_q); | |
| 930 | − return -EINVAL; | |
| 931 | −} | |
| 932 | − | |
| 933 | −static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) | |
| 934 | −{ | |
| 935 | − struct saa7146_fh *fh = __fh; | |
| 936 | − struct saa7146_dev *dev = fh->dev; | |
| 937 | − struct saa7146_vv *vv = dev->vv_data; | |
| 938 | − int err; | |
| 939 | − | |
| 940 | − DEB_D("VIDIOC_STREAMOFF, type:%d\n", type); | |
| 941 | − | |
| 942 | − /* ugly: we need to copy some checks from video_end(), | |
| 943 | − because videobuf_streamoff() relies on the capture running. | |
| 944 | − check and fix this */ | |
| 945 | − if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { | |
| 946 | − DEB_S("not capturing\n"); | |
| 947 | − return 0; | |
| 948 | − } | |
| 949 | − | |
| 950 | − if (vv->video_fh != fh) { | |
| 951 | − DEB_S("capturing, but in another open\n"); | |
| 952 | − return -EBUSY; | |
| 953 | − } | |
| 954 | − | |
| 955 | − err = -EINVAL; | |
| 956 | − if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 957 | − err = videobuf_streamoff(&fh->video_q); | |
| 958 | − else if (type == V4L2_BUF_TYPE_VBI_CAPTURE) | |
| 959 | − err = videobuf_streamoff(&fh->vbi_q); | |
| 960 | − if (0 != err) { | |
| 961 | − DEB_D("warning: videobuf_streamoff() failed\n"); | |
| 962 | − video_end(fh, file); | |
| 963 | − } else { | |
| 964 | − err = video_end(fh, file); | |
| 965 | − } | |
| 966 | − return err; | |
| 967 | −} | |
| 968 | − | |
| 969 | 495 | const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { |
| 970 | 496 | .vidioc_querycap = vidioc_querycap, |
| 971 | 497 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
| 972 | − .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_cap, | |
| 973 | 498 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, |
| 974 | 499 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, |
| 975 | 500 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, |
| 976 | − .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, | |
| 977 | − .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, | |
| 978 | − .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, | |
| 979 | − | |
| 980 | − .vidioc_overlay = vidioc_overlay, | |
| 981 | − .vidioc_g_fbuf = vidioc_g_fbuf, | |
| 982 | − .vidioc_s_fbuf = vidioc_s_fbuf, | |
| 983 | − .vidioc_reqbufs = vidioc_reqbufs, | |
| 984 | − .vidioc_querybuf = vidioc_querybuf, | |
| 985 | − .vidioc_qbuf = vidioc_qbuf, | |
| 986 | − .vidioc_dqbuf = vidioc_dqbuf, | |
| 987 | 501 | .vidioc_g_std = vidioc_g_std, |
| 988 | 502 | .vidioc_s_std = vidioc_s_std, |
| 989 | − .vidioc_streamon = vidioc_streamon, | |
| 990 | − .vidioc_streamoff = vidioc_streamoff, | |
| 991 | 503 | .vidioc_g_parm = vidioc_g_parm, |
| 504 | + .vidioc_reqbufs = vb2_ioctl_reqbufs, | |
| 505 | + .vidioc_create_bufs = vb2_ioctl_create_bufs, | |
| 506 | + .vidioc_querybuf = vb2_ioctl_querybuf, | |
| 507 | + .vidioc_qbuf = vb2_ioctl_qbuf, | |
| 508 | + .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
| 509 | + .vidioc_streamon = vb2_ioctl_streamon, | |
| 510 | + .vidioc_streamoff = vb2_ioctl_streamoff, | |
| 992 | 511 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
| 993 | 512 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
| 994 | 513 | }; |
| @@ -996,16 +515,18 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { · 1 unmodified line | ||
| 996 | 515 | const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = { |
| 997 | 516 | .vidioc_querycap = vidioc_querycap, |
| 998 | 517 | .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, |
| 999 | − | |
| 1000 | − .vidioc_reqbufs = vidioc_reqbufs, | |
| 1001 | − .vidioc_querybuf = vidioc_querybuf, | |
| 1002 | − .vidioc_qbuf = vidioc_qbuf, | |
| 1003 | − .vidioc_dqbuf = vidioc_dqbuf, | |
| 518 | + .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, | |
| 519 | + .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, | |
| 1004 | 520 | .vidioc_g_std = vidioc_g_std, |
| 1005 | 521 | .vidioc_s_std = vidioc_s_std, |
| 1006 | − .vidioc_streamon = vidioc_streamon, | |
| 1007 | − .vidioc_streamoff = vidioc_streamoff, | |
| 1008 | 522 | .vidioc_g_parm = vidioc_g_parm, |
| 523 | + .vidioc_reqbufs = vb2_ioctl_reqbufs, | |
| 524 | + .vidioc_create_bufs = vb2_ioctl_create_bufs, | |
| 525 | + .vidioc_querybuf = vb2_ioctl_querybuf, | |
| 526 | + .vidioc_qbuf = vb2_ioctl_qbuf, | |
| 527 | + .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
| 528 | + .vidioc_streamon = vb2_ioctl_streamon, | |
| 529 | + .vidioc_streamoff = vb2_ioctl_streamoff, | |
| 1009 | 530 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
| 1010 | 531 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
| 1011 | 532 | }; |
| @@ -1019,7 +540,6 @@ static int buffer_activate (struct saa7146_dev *dev, · 7 unmodified lines | ||
| 1019 | 540 | { |
| 1020 | 541 | struct saa7146_vv *vv = dev->vv_data; |
| 1021 | 542 | |
| 1022 | − buf->vb.state = VIDEOBUF_ACTIVE; | |
| 1023 | 543 | saa7146_set_capture(dev,buf,next); |
| 1024 | 544 | |
| 1025 | 545 | mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT); |
| @@ -1033,140 +553,136 @@ static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf * · 7 unmodified lines | ||
| 1033 | 553 | saa7146_pgtable_free(dev->pci, &buf->pt[2]); |
| 1034 | 554 | } |
| 1035 | 555 | |
| 1036 | −static int buffer_prepare(struct videobuf_queue *q, | |
| 1037 | − struct videobuf_buffer *vb, enum v4l2_field field) | |
| 556 | +static int queue_setup(struct vb2_queue *q, | |
| 557 | + unsigned int *num_buffers, unsigned int *num_planes, | |
| 558 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 1038 | 559 | { |
| 1039 | − struct file *file = q->priv_data; | |
| 1040 | − struct saa7146_fh *fh = file->private_data; | |
| 1041 | − struct saa7146_dev *dev = fh->dev; | |
| 1042 | − struct saa7146_vv *vv = dev->vv_data; | |
| 1043 | − struct saa7146_buf *buf = (struct saa7146_buf *)vb; | |
| 1044 | − int size,err = 0; | |
| 1045 | − | |
| 1046 | − DEB_CAP("vbuf:%p\n", vb); | |
| 1047 | − | |
| 1048 | − /* sanity checks */ | |
| 1049 | − if (vv->video_fmt.width < 48 || | |
| 1050 | − vv->video_fmt.height < 32 || | |
| 1051 | − vv->video_fmt.width > vv->standard->h_max_out || | |
| 1052 | − vv->video_fmt.height > vv->standard->v_max_out) { | |
| 1053 | − DEB_D("w (%d) / h (%d) out of bounds\n", | |
| 1054 | − vv->video_fmt.width, vv->video_fmt.height); | |
| 1055 | − return -EINVAL; | |
| 1056 | − } | |
| 560 | + struct saa7146_dev *dev = vb2_get_drv_priv(q); | |
| 561 | + unsigned int size = dev->vv_data->video_fmt.sizeimage; | |
| 1057 | 562 | |
| 1058 | − size = vv->video_fmt.sizeimage; | |
| 1059 | − if (0 != buf->vb.baddr && buf->vb.bsize < size) { | |
| 1060 | − DEB_D("size mismatch\n"); | |
| 1061 | − return -EINVAL; | |
| 1062 | − } | |
| 563 | + if (*num_planes) | |
| 564 | + return sizes[0] < size ? -EINVAL : 0; | |
| 565 | + *num_planes = 1; | |
| 566 | + sizes[0] = size; | |
| 1063 | 567 | |
| 1064 | − DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n", | |
| 1065 | − vv->video_fmt.width, vv->video_fmt.height, | |
| 1066 | − size, v4l2_field_names[vv->video_fmt.field]); | |
| 1067 | − if (buf->vb.width != vv->video_fmt.width || | |
| 1068 | − buf->vb.bytesperline != vv->video_fmt.bytesperline || | |
| 1069 | − buf->vb.height != vv->video_fmt.height || | |
| 1070 | − buf->vb.size != size || | |
| 1071 | − buf->vb.field != field || | |
| 1072 | − buf->vb.field != vv->video_fmt.field || | |
| 1073 | − buf->fmt != &vv->video_fmt) { | |
| 1074 | − saa7146_dma_free(dev,q,buf); | |
| 1075 | − } | |
| 568 | + return 0; | |
| 569 | +} | |
| 1076 | 570 | |
| 1077 | − if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | |
| 1078 | − struct saa7146_format *sfmt; | |
| 571 | +static void buf_queue(struct vb2_buffer *vb) | |
| 572 | +{ | |
| 573 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 574 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 575 | + struct saa7146_dev *dev = vb2_get_drv_priv(vq); | |
| 576 | + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); | |
| 577 | + unsigned long flags; | |
| 1079 | 578 | |
| 1080 | − buf->vb.bytesperline = vv->video_fmt.bytesperline; | |
| 1081 | − buf->vb.width = vv->video_fmt.width; | |
| 1082 | − buf->vb.height = vv->video_fmt.height; | |
| 1083 | − buf->vb.size = size; | |
| 1084 | − buf->vb.field = field; | |
| 1085 | − buf->fmt = &vv->video_fmt; | |
| 1086 | − buf->vb.field = vv->video_fmt.field; | |
| 579 | + spin_lock_irqsave(&dev->slock, flags); | |
| 1087 | 580 | |
| 1088 | − sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); | |
| 581 | + saa7146_buffer_queue(dev, &dev->vv_data->video_dmaq, buf); | |
| 582 | + spin_unlock_irqrestore(&dev->slock, flags); | |
| 583 | +} | |
| 1089 | 584 | |
| 1090 | − release_all_pagetables(dev, buf); | |
| 1091 | − if( 0 != IS_PLANAR(sfmt->trans)) { | |
| 1092 | − saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); | |
| 1093 | − saa7146_pgtable_alloc(dev->pci, &buf->pt[1]); | |
| 1094 | − saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); | |
| 1095 | − } else { | |
| 1096 | − saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); | |
| 1097 | − } | |
| 585 | +static int buf_init(struct vb2_buffer *vb) | |
| 586 | +{ | |
| 587 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 588 | + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); | |
| 589 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 590 | + struct saa7146_dev *dev = vb2_get_drv_priv(vq); | |
| 591 | + struct saa7146_vv *vv = dev->vv_data; | |
| 592 | + struct saa7146_format *sfmt; | |
| 593 | + int ret; | |
| 1098 | 594 | |
| 1099 | − err = videobuf_iolock(q,&buf->vb, &vv->ov_fb); | |
| 1100 | − if (err) | |
| 1101 | − goto oops; | |
| 1102 | − err = saa7146_pgtable_build(dev,buf); | |
| 1103 | − if (err) | |
| 1104 | − goto oops; | |
| 1105 | − } | |
| 1106 | − buf->vb.state = VIDEOBUF_PREPARED; | |
| 1107 | 595 | buf->activate = buffer_activate; |
| 596 | + sfmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat); | |
| 1108 | 597 | |
| 1109 | − return 0; | |
| 1110 | − | |
| 1111 | − oops: | |
| 1112 | − DEB_D("error out\n"); | |
| 1113 | − saa7146_dma_free(dev,q,buf); | |
| 598 | + if (IS_PLANAR(sfmt->trans)) { | |
| 599 | + saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); | |
| 600 | + saa7146_pgtable_alloc(dev->pci, &buf->pt[1]); | |
| 601 | + saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); | |
| 602 | + } else { | |
| 603 | + saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); | |
| 604 | + } | |
| 1114 | 605 | |
| 1115 | − return err; | |
| 606 | + ret = saa7146_pgtable_build(dev, buf); | |
| 607 | + if (ret) | |
| 608 | + release_all_pagetables(dev, buf); | |
| 609 | + return ret; | |
| 1116 | 610 | } |
| 1117 | 611 | |
| 1118 | −static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | |
| 612 | +static int buf_prepare(struct vb2_buffer *vb) | |
| 1119 | 613 | { |
| 1120 | − struct file *file = q->priv_data; | |
| 1121 | − struct saa7146_fh *fh = file->private_data; | |
| 1122 | − struct saa7146_vv *vv = fh->dev->vv_data; | |
| 1123 | − | |
| 1124 | − if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS) | |
| 1125 | − *count = MAX_SAA7146_CAPTURE_BUFFERS; | |
| 1126 | − | |
| 1127 | − *size = vv->video_fmt.sizeimage; | |
| 614 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 615 | + struct saa7146_dev *dev = vb2_get_drv_priv(vq); | |
| 616 | + struct saa7146_vv *vv = dev->vv_data; | |
| 617 | + unsigned int size = vv->video_fmt.sizeimage; | |
| 1128 | 618 | |
| 1129 | − /* check if we exceed the "max_memory" parameter */ | |
| 1130 | − if( (*count * *size) > (max_memory*1048576) ) { | |
| 1131 | − *count = (max_memory*1048576) / *size; | |
| 1132 | − } | |
| 619 | + if (vb2_plane_size(vb, 0) < size) | |
| 620 | + return -EINVAL; | |
| 621 | + vb2_set_plane_payload(vb, 0, size); | |
| 622 | + return 0; | |
| 623 | +} | |
| 1133 | 624 | |
| 1134 | − DEB_CAP("%d buffers, %d bytes each\n", *count, *size); | |
| 625 | +static void buf_cleanup(struct vb2_buffer *vb) | |
| 626 | +{ | |
| 627 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 628 | + struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); | |
| 629 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 630 | + struct saa7146_dev *dev = vb2_get_drv_priv(vq); | |
| 1135 | 631 | |
| 1136 | − return 0; | |
| 632 | + release_all_pagetables(dev, buf); | |
| 1137 | 633 | } |
| 1138 | 634 | |
| 1139 | −static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | |
| 635 | +static void return_buffers(struct vb2_queue *q, int state) | |
| 1140 | 636 | { |
| 1141 | − struct file *file = q->priv_data; | |
| 1142 | − struct saa7146_fh *fh = file->private_data; | |
| 1143 | − struct saa7146_dev *dev = fh->dev; | |
| 1144 | − struct saa7146_vv *vv = dev->vv_data; | |
| 1145 | − struct saa7146_buf *buf = (struct saa7146_buf *)vb; | |
| 637 | + struct saa7146_dev *dev = vb2_get_drv_priv(q); | |
| 638 | + struct saa7146_dmaqueue *dq = &dev->vv_data->video_dmaq; | |
| 639 | + struct saa7146_buf *buf; | |
| 1146 | 640 | |
| 1147 | − DEB_CAP("vbuf:%p\n", vb); | |
| 1148 | − saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf); | |
| 641 | + if (dq->curr) { | |
| 642 | + buf = dq->curr; | |
| 643 | + dq->curr = NULL; | |
| 644 | + vb2_buffer_done(&buf->vb.vb2_buf, state); | |
| 645 | + } | |
| 646 | + while (!list_empty(&dq->queue)) { | |
| 647 | + buf = list_entry(dq->queue.next, struct saa7146_buf, list); | |
| 648 | + list_del(&buf->list); | |
| 649 | + vb2_buffer_done(&buf->vb.vb2_buf, state); | |
| 650 | + } | |
| 1149 | 651 | } |
| 1150 | 652 | |
| 1151 | −static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | |
| 653 | +static int start_streaming(struct vb2_queue *q, unsigned int count) | |
| 1152 | 654 | { |
| 1153 | − struct file *file = q->priv_data; | |
| 1154 | − struct saa7146_fh *fh = file->private_data; | |
| 1155 | − struct saa7146_dev *dev = fh->dev; | |
| 1156 | − struct saa7146_buf *buf = (struct saa7146_buf *)vb; | |
| 655 | + struct saa7146_dev *dev = vb2_get_drv_priv(q); | |
| 656 | + int ret; | |
| 1157 | 657 | |
| 1158 | − DEB_CAP("vbuf:%p\n", vb); | |
| 658 | + if (!vb2_is_streaming(&dev->vv_data->video_dmaq.q)) | |
| 659 | + dev->vv_data->seqnr = 0; | |
| 660 | + ret = video_begin(dev); | |
| 661 | + if (ret) | |
| 662 | + return_buffers(q, VB2_BUF_STATE_QUEUED); | |
| 663 | + return ret; | |
| 664 | +} | |
| 1159 | 665 | |
| 1160 | − saa7146_dma_free(dev,q,buf); | |
| 666 | +static void stop_streaming(struct vb2_queue *q) | |
| 667 | +{ | |
| 668 | + struct saa7146_dev *dev = vb2_get_drv_priv(q); | |
| 669 | + struct saa7146_dmaqueue *dq = &dev->vv_data->video_dmaq; | |
| 1161 | 670 | |
| 1162 | − release_all_pagetables(dev, buf); | |
| 671 | + del_timer(&dq->timeout); | |
| 672 | + video_end(dev); | |
| 673 | + return_buffers(q, VB2_BUF_STATE_ERROR); | |
| 1163 | 674 | } |
| 1164 | 675 | |
| 1165 | −static const struct videobuf_queue_ops video_qops = { | |
| 1166 | − .buf_setup = buffer_setup, | |
| 1167 | − .buf_prepare = buffer_prepare, | |
| 1168 | − .buf_queue = buffer_queue, | |
| 1169 | − .buf_release = buffer_release, | |
| 676 | +const struct vb2_ops video_qops = { | |
| 677 | + .queue_setup = queue_setup, | |
| 678 | + .buf_queue = buf_queue, | |
| 679 | + .buf_init = buf_init, | |
| 680 | + .buf_prepare = buf_prepare, | |
| 681 | + .buf_cleanup = buf_cleanup, | |
| 682 | + .start_streaming = start_streaming, | |
| 683 | + .stop_streaming = stop_streaming, | |
| 684 | + .wait_prepare = vb2_ops_wait_prepare, | |
| 685 | + .wait_finish = vb2_ops_wait_finish, | |
| 1170 | 686 | }; |
| 1171 | 687 | |
| 1172 | 688 | /********************************************************************************/ |
| @@ -1187,38 +703,6 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) · 14 unmodified lines | ||
| 1187 | 703 | vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A; |
| 1188 | 704 | } |
| 1189 | 705 | |
| 1190 | − | |
| 1191 | −static int video_open(struct saa7146_dev *dev, struct file *file) | |
| 1192 | −{ | |
| 1193 | − struct saa7146_fh *fh = file->private_data; | |
| 1194 | − | |
| 1195 | − videobuf_queue_sg_init(&fh->video_q, &video_qops, | |
| 1196 | − &dev->pci->dev, &dev->slock, | |
| 1197 | − V4L2_BUF_TYPE_VIDEO_CAPTURE, | |
| 1198 | − V4L2_FIELD_INTERLACED, | |
| 1199 | − sizeof(struct saa7146_buf), | |
| 1200 | − file, &dev->v4l2_lock); | |
| 1201 | − | |
| 1202 | − return 0; | |
| 1203 | −} | |
| 1204 | − | |
| 1205 | − | |
| 1206 | −static void video_close(struct saa7146_dev *dev, struct file *file) | |
| 1207 | −{ | |
| 1208 | − struct saa7146_fh *fh = file->private_data; | |
| 1209 | − struct saa7146_vv *vv = dev->vv_data; | |
| 1210 | − struct videobuf_queue *q = &fh->video_q; | |
| 1211 | − | |
| 1212 | − if (IS_CAPTURE_ACTIVE(fh) != 0) | |
| 1213 | − video_end(fh, file); | |
| 1214 | − else if (IS_OVERLAY_ACTIVE(fh) != 0) | |
| 1215 | − saa7146_stop_preview(fh); | |
| 1216 | − | |
| 1217 | − videobuf_stop(q); | |
| 1218 | − /* hmm, why is this function declared void? */ | |
| 1219 | −} | |
| 1220 | − | |
| 1221 | − | |
| 1222 | 706 | static void video_irq_done(struct saa7146_dev *dev, unsigned long st) |
| 1223 | 707 | { |
| 1224 | 708 | struct saa7146_vv *vv = dev->vv_data; |
| @@ -1228,59 +712,14 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st) · 3 unmodified lines | ||
| 1228 | 712 | DEB_CAP("called\n"); |
| 1229 | 713 | |
| 1230 | 714 | /* only finish the buffer if we have one... */ |
| 1231 | − if( NULL != q->curr ) { | |
| 1232 | − saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); | |
| 1233 | − } | |
| 715 | + if (q->curr) | |
| 716 | + saa7146_buffer_finish(dev, q, VB2_BUF_STATE_DONE); | |
| 1234 | 717 | saa7146_buffer_next(dev,q,0); |
| 1235 | 718 | |
| 1236 | 719 | spin_unlock(&dev->slock); |
| 1237 | 720 | } |
| 1238 | 721 | |
| 1239 | −static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | |
| 1240 | −{ | |
| 1241 | − struct saa7146_fh *fh = file->private_data; | |
| 1242 | − struct saa7146_dev *dev = fh->dev; | |
| 1243 | − struct saa7146_vv *vv = dev->vv_data; | |
| 1244 | − ssize_t ret = 0; | |
| 1245 | − | |
| 1246 | − DEB_EE("called\n"); | |
| 1247 | − | |
| 1248 | − if ((vv->video_status & STATUS_CAPTURE) != 0) { | |
| 1249 | − /* fixme: should we allow read() captures while streaming capture? */ | |
| 1250 | − if (vv->video_fh == fh) { | |
| 1251 | − DEB_S("already capturing\n"); | |
| 1252 | − return -EBUSY; | |
| 1253 | − } | |
| 1254 | − DEB_S("already capturing in another open\n"); | |
| 1255 | − return -EBUSY; | |
| 1256 | − } | |
| 1257 | − | |
| 1258 | − ret = video_begin(fh); | |
| 1259 | − if( 0 != ret) { | |
| 1260 | − goto out; | |
| 1261 | − } | |
| 1262 | − | |
| 1263 | − ret = videobuf_read_one(&fh->video_q , data, count, ppos, | |
| 1264 | − file->f_flags & O_NONBLOCK); | |
| 1265 | − if (ret != 0) { | |
| 1266 | − video_end(fh, file); | |
| 1267 | − } else { | |
| 1268 | − ret = video_end(fh, file); | |
| 1269 | − } | |
| 1270 | −out: | |
| 1271 | − /* restart overlay if it was active before */ | |
| 1272 | − if (vv->ov_suspend != NULL) { | |
| 1273 | − saa7146_start_preview(vv->ov_suspend); | |
| 1274 | − vv->ov_suspend = NULL; | |
| 1275 | − } | |
| 1276 | − | |
| 1277 | − return ret; | |
| 1278 | −} | |
| 1279 | − | |
| 1280 | 722 | const struct saa7146_use_ops saa7146_video_uops = { |
| 1281 | 723 | .init = video_init, |
| 1282 | − .open = video_open, | |
| 1283 | − .release = video_close, | |
| 1284 | 724 | .irq_done = video_irq_done, |
| 1285 | − .read = video_read, | |
| 1286 | 725 | }; |
| @@ -1171,10 +1171,11 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf, · 1170 unmodified lines | ||
| 1171 | 1171 | return -ERESTARTSYS; |
| 1172 | 1172 | if (vb2_queue_is_busy(vdev->queue, file)) |
| 1173 | 1173 | goto exit; |
| 1174 | + vdev->queue->owner = file->private_data; | |
| 1174 | 1175 | err = vb2_read(vdev->queue, buf, count, ppos, |
| 1175 | 1176 | file->f_flags & O_NONBLOCK); |
| 1176 | − if (vdev->queue->fileio) | |
| 1177 | − vdev->queue->owner = file->private_data; | |
| 1177 | + if (!vdev->queue->fileio) | |
| 1178 | + vdev->queue->owner = NULL; | |
| 1178 | 1179 | exit: |
| 1179 | 1180 | if (lock) |
| 1180 | 1181 | mutex_unlock(lock); |
| @@ -11070,7 +11070,7 @@ ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode) · 11069 unmodified lines | ||
| 11070 | 11070 | sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC; |
| 11071 | 11071 | break; |
| 11072 | 11072 | default: |
| 11073 | − /* Unknow sleep mode */ | |
| 11073 | + /* Unknown sleep mode */ | |
| 11074 | 11074 | return -EINVAL; |
| 11075 | 11075 | } |
| 11076 | 11076 | |
| @@ -1585,7 +1585,7 @@ static int ctrl_power_mode(struct drxk_state *state, enum drx_power_mode *mode) · 1584 unmodified lines | ||
| 1585 | 1585 | sio_cc_pwd_mode = SIO_CC_PWD_MODE_LEVEL_OSC; |
| 1586 | 1586 | break; |
| 1587 | 1587 | default: |
| 1588 | − /* Unknow sleep mode */ | |
| 1588 | + /* Unknown sleep mode */ | |
| 1589 | 1589 | return -EINVAL; |
| 1590 | 1590 | } |
| 1591 | 1591 | |
| @@ -1463,7 +1463,7 @@ err: · 1462 unmodified lines | ||
| 1463 | 1463 | return ret; |
| 1464 | 1464 | } |
| 1465 | 1465 | |
| 1466 | −static int rtl2832_sdr_remove(struct platform_device *pdev) | |
| 1466 | +static void rtl2832_sdr_remove(struct platform_device *pdev) | |
| 1467 | 1467 | { |
| 1468 | 1468 | struct rtl2832_sdr_dev *dev = platform_get_drvdata(pdev); |
| 1469 | 1469 | |
| @@ -1479,8 +1479,6 @@ static int rtl2832_sdr_remove(struct platform_device *pdev) · 9 unmodified lines | ||
| 1479 | 1479 | mutex_unlock(&dev->vb_queue_lock); |
| 1480 | 1480 | v4l2_device_put(&dev->v4l2_dev); |
| 1481 | 1481 | module_put(pdev->dev.parent->driver->owner); |
| 1482 | − | |
| 1483 | − return 0; | |
| 1484 | 1482 | } |
| 1485 | 1483 | |
| 1486 | 1484 | static struct platform_driver rtl2832_sdr_driver = { |
| @@ -1488,7 +1486,7 @@ static struct platform_driver rtl2832_sdr_driver = { · 1 unmodified line | ||
| 1488 | 1486 | .name = "rtl2832_sdr", |
| 1489 | 1487 | }, |
| 1490 | 1488 | .probe = rtl2832_sdr_probe, |
| 1491 | − .remove = rtl2832_sdr_remove, | |
| 1489 | + .remove_new = rtl2832_sdr_remove, | |
| 1492 | 1490 | }; |
| 1493 | 1491 | module_platform_driver(rtl2832_sdr_driver); |
| 1494 | 1492 | |
| @@ -515,7 +515,7 @@ err: · 514 unmodified lines | ||
| 515 | 515 | return ret; |
| 516 | 516 | } |
| 517 | 517 | |
| 518 | −static int zd1301_demod_remove(struct platform_device *pdev) | |
| 518 | +static void zd1301_demod_remove(struct platform_device *pdev) | |
| 519 | 519 | { |
| 520 | 520 | struct zd1301_demod_dev *dev = platform_get_drvdata(pdev); |
| 521 | 521 | |
| @@ -523,8 +523,6 @@ static int zd1301_demod_remove(struct platform_device *pdev) · 1 unmodified line | ||
| 523 | 523 | |
| 524 | 524 | i2c_del_adapter(&dev->adapter); |
| 525 | 525 | kfree(dev); |
| 526 | − | |
| 527 | − return 0; | |
| 528 | 526 | } |
| 529 | 527 | |
| 530 | 528 | static struct platform_driver zd1301_demod_driver = { |
| @@ -533,7 +531,7 @@ static struct platform_driver zd1301_demod_driver = { · 2 unmodified lines | ||
| 533 | 531 | .suppress_bind_attrs = true, |
| 534 | 532 | }, |
| 535 | 533 | .probe = zd1301_demod_probe, |
| 536 | − .remove = zd1301_demod_remove, | |
| 534 | + .remove_new = zd1301_demod_remove, | |
| 537 | 535 | }; |
| 538 | 536 | module_platform_driver(zd1301_demod_driver); |
| 539 | 537 | |
| @@ -267,16 +267,6 @@ config VIDEO_MT9M001 · 266 unmodified lines | ||
| 267 | 267 | This driver supports MT9M001 cameras from Micron, monochrome |
| 268 | 268 | and colour models. |
| 269 | 269 | |
| 270 | −config VIDEO_MT9M032 | |
| 271 | − tristate "MT9M032 camera sensor support" | |
| 272 | − depends on I2C && VIDEO_DEV | |
| 273 | − select MEDIA_CONTROLLER | |
| 274 | − select VIDEO_V4L2_SUBDEV_API | |
| 275 | − select VIDEO_APTINA_PLL | |
| 276 | − help | |
| 277 | − This driver supports MT9M032 camera sensors from Aptina, monochrome | |
| 278 | − models only. | |
| 279 | − | |
| 280 | 270 | config VIDEO_MT9M111 |
| 281 | 271 | tristate "mt9m111, mt9m112 and mt9m131 support" |
| 282 | 272 | depends on I2C && VIDEO_DEV |
| @@ -296,15 +286,6 @@ config VIDEO_MT9P031 · 13 unmodified lines | ||
| 296 | 286 | This is a Video4Linux2 sensor driver for the Aptina |
| 297 | 287 | (Micron) mt9p031 5 Mpixel camera. |
| 298 | 288 | |
| 299 | −config VIDEO_MT9T001 | |
| 300 | − tristate "Aptina MT9T001 support" | |
| 301 | − depends on I2C && VIDEO_DEV | |
| 302 | − select MEDIA_CONTROLLER | |
| 303 | − select VIDEO_V4L2_SUBDEV_API | |
| 304 | − help | |
| 305 | − This is a Video4Linux2 sensor driver for the Aptina | |
| 306 | − (Micron) mt0t001 3 Mpixel camera. | |
| 307 | − | |
| 308 | 289 | config VIDEO_MT9T112 |
| 309 | 290 | tristate "Aptina MT9T111/MT9T112 support" |
| 310 | 291 | depends on I2C && VIDEO_DEV |
| @@ -344,14 +325,6 @@ config VIDEO_MT9V111 · 33 unmodified lines | ||
| 344 | 325 | To compile this driver as a module, choose M here: the |
| 345 | 326 | module will be called mt9v111. |
| 346 | 327 | |
| 347 | −config VIDEO_NOON010PC30 | |
| 348 | − tristate "Siliconfile NOON010PC30 sensor support" | |
| 349 | − depends on I2C && VIDEO_DEV | |
| 350 | − select MEDIA_CONTROLLER | |
| 351 | − select VIDEO_V4L2_SUBDEV_API | |
| 352 | − help | |
| 353 | − This driver supports NOON010PC30 CIF camera from Siliconfile | |
| 354 | − | |
| 355 | 328 | config VIDEO_OG01A1B |
| 356 | 329 | tristate "OmniVision OG01A1B sensor support" |
| 357 | 330 | depends on I2C && VIDEO_DEV |
| @@ -462,6 +435,7 @@ config VIDEO_OV2685 · 104 unmodified lines | ||
| 462 | 435 | tristate "OmniVision OV2685 sensor support" |
| 463 | 436 | depends on VIDEO_DEV && I2C |
| 464 | 437 | select MEDIA_CONTROLLER |
| 438 | + select VIDEO_V4L2_SUBDEV_API | |
| 465 | 439 | select V4L2_FWNODE |
| 466 | 440 | help |
| 467 | 441 | This is a Video4Linux2 sensor driver for the OmniVision |
| @@ -810,21 +784,6 @@ config VIDEO_S5K6A3 · 342 unmodified lines | ||
| 810 | 784 | This is a V4L2 sensor driver for Samsung S5K6A3 raw |
| 811 | 785 | camera sensor. |
| 812 | 786 | |
| 813 | −config VIDEO_S5K6AA | |
| 814 | − tristate "Samsung S5K6AAFX sensor support" | |
| 815 | − depends on I2C && VIDEO_DEV | |
| 816 | − select MEDIA_CONTROLLER | |
| 817 | − select VIDEO_V4L2_SUBDEV_API | |
| 818 | − help | |
| 819 | − This is a V4L2 sensor driver for Samsung S5K6AA(FX) 1.3M | |
| 820 | − camera sensor with an embedded SoC image signal processor. | |
| 821 | − | |
| 822 | −config VIDEO_SR030PC30 | |
| 823 | − tristate "Siliconfile SR030PC30 sensor support" | |
| 824 | − depends on I2C && VIDEO_DEV | |
| 825 | − help | |
| 826 | − This driver supports SR030PC30 VGA camera from Siliconfile | |
| 827 | − | |
| 828 | 787 | config VIDEO_ST_VGXY61 |
| 829 | 788 | tristate "ST VGXY61 sensor support" |
| 830 | 789 | depends on OF && GPIOLIB && VIDEO_DEV && I2C |
| @@ -835,19 +794,8 @@ config VIDEO_ST_VGXY61 · 4 unmodified lines | ||
| 835 | 794 | This is a Video4Linux2 sensor driver for the ST VGXY61 |
| 836 | 795 | camera sensor. |
| 837 | 796 | |
| 838 | −config VIDEO_VS6624 | |
| 839 | − tristate "ST VS6624 sensor support" | |
| 840 | − depends on VIDEO_DEV && I2C | |
| 841 | − help | |
| 842 | − This is a Video4Linux2 sensor driver for the ST VS6624 | |
| 843 | − camera. | |
| 844 | − | |
| 845 | − To compile this driver as a module, choose M here: the | |
| 846 | − module will be called vs6624. | |
| 847 | − | |
| 848 | 797 | source "drivers/media/i2c/ccs/Kconfig" |
| 849 | 798 | source "drivers/media/i2c/et8ek8/Kconfig" |
| 850 | −source "drivers/media/i2c/m5mols/Kconfig" | |
| 851 | 799 | |
| 852 | 800 | endmenu |
| 853 | 801 | |
| @@ -1453,20 +1401,6 @@ endmenu · 599 unmodified lines | ||
| 1453 | 1401 | menu "Video encoders" |
| 1454 | 1402 | visible if !MEDIA_HIDE_ANCILLARY_SUBDRV |
| 1455 | 1403 | |
| 1456 | −config VIDEO_AD9389B | |
| 1457 | − tristate "Analog Devices AD9389B encoder" | |
| 1458 | − depends on VIDEO_DEV && I2C | |
| 1459 | − select MEDIA_CONTROLLER | |
| 1460 | − select VIDEO_V4L2_SUBDEV_API | |
| 1461 | − | |
| 1462 | − help | |
| 1463 | − Support for the Analog Devices AD9389B video encoder. | |
| 1464 | − | |
| 1465 | − This is a Analog Devices HDMI transmitter. | |
| 1466 | − | |
| 1467 | − To compile this driver as a module, choose M here: the | |
| 1468 | − module will be called ad9389b. | |
| 1469 | − | |
| 1470 | 1404 | config VIDEO_ADV7170 |
| 1471 | 1405 | tristate "Analog Devices ADV7170 video encoder" |
| 1472 | 1406 | depends on VIDEO_DEV && I2C |
| @@ -4,7 +4,6 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | obj-$(CONFIG_SDR_MAX2175) += max2175.o |
| 6 | 6 | obj-$(CONFIG_VIDEO_AD5820) += ad5820.o |
| 7 | −obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o | |
| 8 | 7 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o |
| 9 | 8 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o |
| 10 | 9 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o |
| @@ -56,21 +55,17 @@ obj-$(CONFIG_VIDEO_KS0127) += ks0127.o · 45 unmodified lines | ||
| 56 | 55 | obj-$(CONFIG_VIDEO_LM3560) += lm3560.o |
| 57 | 56 | obj-$(CONFIG_VIDEO_LM3646) += lm3646.o |
| 58 | 57 | obj-$(CONFIG_VIDEO_M52790) += m52790.o |
| 59 | −obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ | |
| 60 | 58 | obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o |
| 61 | 59 | obj-$(CONFIG_VIDEO_MAX9286) += max9286.o |
| 62 | 60 | obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o |
| 63 | 61 | obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o |
| 64 | 62 | obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o |
| 65 | −obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o | |
| 66 | 63 | obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o |
| 67 | 64 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o |
| 68 | −obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o | |
| 69 | 65 | obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o |
| 70 | 66 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o |
| 71 | 67 | obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o |
| 72 | 68 | obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o |
| 73 | −obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | |
| 74 | 69 | obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o |
| 75 | 70 | obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o |
| 76 | 71 | obj-$(CONFIG_VIDEO_OV08D10) += ov08d10.o |
| @@ -110,7 +105,6 @@ obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o · 33 unmodified lines | ||
| 110 | 105 | obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ |
| 111 | 106 | obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o |
| 112 | 107 | obj-$(CONFIG_VIDEO_S5K6A3) += s5k6a3.o |
| 113 | −obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o | |
| 114 | 108 | obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o |
| 115 | 109 | obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o |
| 116 | 110 | obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o |
| @@ -119,7 +113,6 @@ obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o · 2 unmodified lines | ||
| 119 | 113 | obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o |
| 120 | 114 | obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o |
| 121 | 115 | obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o |
| 122 | −obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | |
| 123 | 116 | obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o |
| 124 | 117 | obj-$(CONFIG_VIDEO_ST_VGXY61) += st-vgxy61.o |
| 125 | 118 | obj-$(CONFIG_VIDEO_TC358743) += tc358743.o |
| @@ -145,6 +138,5 @@ obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o · 19 unmodified lines | ||
| 145 | 138 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o |
| 146 | 139 | obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o |
| 147 | 140 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o |
| 148 | −obj-$(CONFIG_VIDEO_VS6624) += vs6624.o | |
| 149 | 141 | obj-$(CONFIG_VIDEO_WM8739) += wm8739.o |
| 150 | 142 | obj-$(CONFIG_VIDEO_WM8775) += wm8775.o |
| @@ -1,1215 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Analog Devices AD9389B/AD9889B video encoder driver | |
| 4 | − * | |
| 5 | − * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | |
| 6 | − */ | |
| 7 | − | |
| 8 | −/* | |
| 9 | − * References (c = chapter, p = page): | |
| 10 | − * REF_01 - Analog Devices, Programming Guide, AD9889B/AD9389B, | |
| 11 | − * HDMI Transitter, Rev. A, October 2010 | |
| 12 | − */ | |
| 13 | − | |
| 14 | −#include <linux/kernel.h> | |
| 15 | −#include <linux/module.h> | |
| 16 | −#include <linux/slab.h> | |
| 17 | −#include <linux/i2c.h> | |
| 18 | −#include <linux/delay.h> | |
| 19 | −#include <linux/videodev2.h> | |
| 20 | −#include <linux/workqueue.h> | |
| 21 | −#include <linux/v4l2-dv-timings.h> | |
| 22 | −#include <media/v4l2-device.h> | |
| 23 | −#include <media/v4l2-common.h> | |
| 24 | −#include <media/v4l2-dv-timings.h> | |
| 25 | −#include <media/v4l2-ctrls.h> | |
| 26 | −#include <media/i2c/ad9389b.h> | |
| 27 | − | |
| 28 | −static int debug; | |
| 29 | −module_param(debug, int, 0644); | |
| 30 | −MODULE_PARM_DESC(debug, "debug level (0-2)"); | |
| 31 | − | |
| 32 | −MODULE_DESCRIPTION("Analog Devices AD9389B/AD9889B video encoder driver"); | |
| 33 | −MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); | |
| 34 | −MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>"); | |
| 35 | −MODULE_LICENSE("GPL"); | |
| 36 | − | |
| 37 | −#define MASK_AD9389B_EDID_RDY_INT 0x04 | |
| 38 | −#define MASK_AD9389B_MSEN_INT 0x40 | |
| 39 | −#define MASK_AD9389B_HPD_INT 0x80 | |
| 40 | − | |
| 41 | −#define MASK_AD9389B_HPD_DETECT 0x40 | |
| 42 | −#define MASK_AD9389B_MSEN_DETECT 0x20 | |
| 43 | −#define MASK_AD9389B_EDID_RDY 0x10 | |
| 44 | − | |
| 45 | −#define EDID_MAX_RETRIES (8) | |
| 46 | −#define EDID_DELAY 250 | |
| 47 | −#define EDID_MAX_SEGM 8 | |
| 48 | − | |
| 49 | −/* | |
| 50 | −********************************************************************** | |
| 51 | −* | |
| 52 | −* Arrays with configuration parameters for the AD9389B | |
| 53 | −* | |
| 54 | −********************************************************************** | |
| 55 | −*/ | |
| 56 | − | |
| 57 | −struct ad9389b_state_edid { | |
| 58 | − /* total number of blocks */ | |
| 59 | − u32 blocks; | |
| 60 | − /* Number of segments read */ | |
| 61 | − u32 segments; | |
| 62 | − u8 data[EDID_MAX_SEGM * 256]; | |
| 63 | − /* Number of EDID read retries left */ | |
| 64 | − unsigned read_retries; | |
| 65 | −}; | |
| 66 | − | |
| 67 | −struct ad9389b_state { | |
| 68 | − struct ad9389b_platform_data pdata; | |
| 69 | − struct v4l2_subdev sd; | |
| 70 | − struct media_pad pad; | |
| 71 | − struct v4l2_ctrl_handler hdl; | |
| 72 | − int chip_revision; | |
| 73 | − /* Is the ad9389b powered on? */ | |
| 74 | − bool power_on; | |
| 75 | − /* Did we receive hotplug and rx-sense signals? */ | |
| 76 | − bool have_monitor; | |
| 77 | − /* timings from s_dv_timings */ | |
| 78 | − struct v4l2_dv_timings dv_timings; | |
| 79 | − /* controls */ | |
| 80 | − struct v4l2_ctrl *hdmi_mode_ctrl; | |
| 81 | − struct v4l2_ctrl *hotplug_ctrl; | |
| 82 | − struct v4l2_ctrl *rx_sense_ctrl; | |
| 83 | − struct v4l2_ctrl *have_edid0_ctrl; | |
| 84 | − struct v4l2_ctrl *rgb_quantization_range_ctrl; | |
| 85 | − struct i2c_client *edid_i2c_client; | |
| 86 | − struct ad9389b_state_edid edid; | |
| 87 | − /* Running counter of the number of detected EDIDs (for debugging) */ | |
| 88 | − unsigned edid_detect_counter; | |
| 89 | − struct delayed_work edid_handler; /* work entry */ | |
| 90 | −}; | |
| 91 | − | |
| 92 | −static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd); | |
| 93 | −static bool ad9389b_check_edid_status(struct v4l2_subdev *sd); | |
| 94 | −static void ad9389b_setup(struct v4l2_subdev *sd); | |
| 95 | −static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq); | |
| 96 | −static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq); | |
| 97 | − | |
| 98 | −static inline struct ad9389b_state *get_ad9389b_state(struct v4l2_subdev *sd) | |
| 99 | −{ | |
| 100 | − return container_of(sd, struct ad9389b_state, sd); | |
| 101 | −} | |
| 102 | − | |
| 103 | −static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | |
| 104 | −{ | |
| 105 | − return &container_of(ctrl->handler, struct ad9389b_state, hdl)->sd; | |
| 106 | −} | |
| 107 | − | |
| 108 | −/* ------------------------ I2C ----------------------------------------------- */ | |
| 109 | − | |
| 110 | −static int ad9389b_rd(struct v4l2_subdev *sd, u8 reg) | |
| 111 | −{ | |
| 112 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 113 | − | |
| 114 | − return i2c_smbus_read_byte_data(client, reg); | |
| 115 | −} | |
| 116 | − | |
| 117 | −static int ad9389b_wr(struct v4l2_subdev *sd, u8 reg, u8 val) | |
| 118 | −{ | |
| 119 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 120 | − int ret; | |
| 121 | − int i; | |
| 122 | − | |
| 123 | − for (i = 0; i < 3; i++) { | |
| 124 | − ret = i2c_smbus_write_byte_data(client, reg, val); | |
| 125 | − if (ret == 0) | |
| 126 | − return 0; | |
| 127 | − } | |
| 128 | − v4l2_err(sd, "%s: failed reg 0x%x, val 0x%x\n", __func__, reg, val); | |
| 129 | − return ret; | |
| 130 | −} | |
| 131 | − | |
| 132 | −/* To set specific bits in the register, a clear-mask is given (to be AND-ed), | |
| 133 | − and then the value-mask (to be OR-ed). */ | |
| 134 | −static inline void ad9389b_wr_and_or(struct v4l2_subdev *sd, u8 reg, | |
| 135 | − u8 clr_mask, u8 val_mask) | |
| 136 | −{ | |
| 137 | − ad9389b_wr(sd, reg, (ad9389b_rd(sd, reg) & clr_mask) | val_mask); | |
| 138 | −} | |
| 139 | − | |
| 140 | −static void ad9389b_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf) | |
| 141 | −{ | |
| 142 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 143 | − int i; | |
| 144 | − | |
| 145 | − v4l2_dbg(1, debug, sd, "%s:\n", __func__); | |
| 146 | − | |
| 147 | − for (i = 0; i < len; i++) | |
| 148 | − buf[i] = i2c_smbus_read_byte_data(state->edid_i2c_client, i); | |
| 149 | −} | |
| 150 | − | |
| 151 | −static inline bool ad9389b_have_hotplug(struct v4l2_subdev *sd) | |
| 152 | −{ | |
| 153 | − return ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT; | |
| 154 | −} | |
| 155 | − | |
| 156 | −static inline bool ad9389b_have_rx_sense(struct v4l2_subdev *sd) | |
| 157 | −{ | |
| 158 | − return ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT; | |
| 159 | −} | |
| 160 | − | |
| 161 | −static void ad9389b_csc_conversion_mode(struct v4l2_subdev *sd, u8 mode) | |
| 162 | −{ | |
| 163 | − ad9389b_wr_and_or(sd, 0x17, 0xe7, (mode & 0x3)<<3); | |
| 164 | − ad9389b_wr_and_or(sd, 0x18, 0x9f, (mode & 0x3)<<5); | |
| 165 | −} | |
| 166 | − | |
| 167 | −static void ad9389b_csc_coeff(struct v4l2_subdev *sd, | |
| 168 | − u16 A1, u16 A2, u16 A3, u16 A4, | |
| 169 | − u16 B1, u16 B2, u16 B3, u16 B4, | |
| 170 | − u16 C1, u16 C2, u16 C3, u16 C4) | |
| 171 | −{ | |
| 172 | − /* A */ | |
| 173 | − ad9389b_wr_and_or(sd, 0x18, 0xe0, A1>>8); | |
| 174 | − ad9389b_wr(sd, 0x19, A1); | |
| 175 | − ad9389b_wr_and_or(sd, 0x1A, 0xe0, A2>>8); | |
| 176 | − ad9389b_wr(sd, 0x1B, A2); | |
| 177 | − ad9389b_wr_and_or(sd, 0x1c, 0xe0, A3>>8); | |
| 178 | − ad9389b_wr(sd, 0x1d, A3); | |
| 179 | − ad9389b_wr_and_or(sd, 0x1e, 0xe0, A4>>8); | |
| 180 | − ad9389b_wr(sd, 0x1f, A4); | |
| 181 | − | |
| 182 | − /* B */ | |
| 183 | − ad9389b_wr_and_or(sd, 0x20, 0xe0, B1>>8); | |
| 184 | − ad9389b_wr(sd, 0x21, B1); | |
| 185 | − ad9389b_wr_and_or(sd, 0x22, 0xe0, B2>>8); | |
| 186 | − ad9389b_wr(sd, 0x23, B2); | |
| 187 | − ad9389b_wr_and_or(sd, 0x24, 0xe0, B3>>8); | |
| 188 | − ad9389b_wr(sd, 0x25, B3); | |
| 189 | − ad9389b_wr_and_or(sd, 0x26, 0xe0, B4>>8); | |
| 190 | − ad9389b_wr(sd, 0x27, B4); | |
| 191 | − | |
| 192 | − /* C */ | |
| 193 | − ad9389b_wr_and_or(sd, 0x28, 0xe0, C1>>8); | |
| 194 | − ad9389b_wr(sd, 0x29, C1); | |
| 195 | − ad9389b_wr_and_or(sd, 0x2A, 0xe0, C2>>8); | |
| 196 | − ad9389b_wr(sd, 0x2B, C2); | |
| 197 | − ad9389b_wr_and_or(sd, 0x2C, 0xe0, C3>>8); | |
| 198 | − ad9389b_wr(sd, 0x2D, C3); | |
| 199 | − ad9389b_wr_and_or(sd, 0x2E, 0xe0, C4>>8); | |
| 200 | − ad9389b_wr(sd, 0x2F, C4); | |
| 201 | −} | |
| 202 | − | |
| 203 | −static void ad9389b_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable) | |
| 204 | −{ | |
| 205 | − if (enable) { | |
| 206 | − u8 csc_mode = 0; | |
| 207 | − | |
| 208 | − ad9389b_csc_conversion_mode(sd, csc_mode); | |
| 209 | − ad9389b_csc_coeff(sd, | |
| 210 | − 4096-564, 0, 0, 256, | |
| 211 | − 0, 4096-564, 0, 256, | |
| 212 | − 0, 0, 4096-564, 256); | |
| 213 | − /* enable CSC */ | |
| 214 | − ad9389b_wr_and_or(sd, 0x3b, 0xfe, 0x1); | |
| 215 | − /* AVI infoframe: Limited range RGB (16-235) */ | |
| 216 | − ad9389b_wr_and_or(sd, 0xcd, 0xf9, 0x02); | |
| 217 | − } else { | |
| 218 | − /* disable CSC */ | |
| 219 | − ad9389b_wr_and_or(sd, 0x3b, 0xfe, 0x0); | |
| 220 | − /* AVI infoframe: Full range RGB (0-255) */ | |
| 221 | − ad9389b_wr_and_or(sd, 0xcd, 0xf9, 0x04); | |
| 222 | − } | |
| 223 | −} | |
| 224 | − | |
| 225 | −static void ad9389b_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd) | |
| 226 | −{ | |
| 227 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 228 | − | |
| 229 | − if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { | |
| 230 | − /* CE format, not IT */ | |
| 231 | − ad9389b_wr_and_or(sd, 0xcd, 0xbf, 0x00); | |
| 232 | − } else { | |
| 233 | − /* IT format */ | |
| 234 | − ad9389b_wr_and_or(sd, 0xcd, 0xbf, 0x40); | |
| 235 | − } | |
| 236 | −} | |
| 237 | − | |
| 238 | −static int ad9389b_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl) | |
| 239 | −{ | |
| 240 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 241 | − | |
| 242 | − switch (ctrl->val) { | |
| 243 | − case V4L2_DV_RGB_RANGE_AUTO: | |
| 244 | − /* automatic */ | |
| 245 | − if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { | |
| 246 | − /* CE format, RGB limited range (16-235) */ | |
| 247 | − ad9389b_csc_rgb_full2limit(sd, true); | |
| 248 | − } else { | |
| 249 | − /* not CE format, RGB full range (0-255) */ | |
| 250 | − ad9389b_csc_rgb_full2limit(sd, false); | |
| 251 | − } | |
| 252 | − break; | |
| 253 | − case V4L2_DV_RGB_RANGE_LIMITED: | |
| 254 | − /* RGB limited range (16-235) */ | |
| 255 | − ad9389b_csc_rgb_full2limit(sd, true); | |
| 256 | − break; | |
| 257 | − case V4L2_DV_RGB_RANGE_FULL: | |
| 258 | − /* RGB full range (0-255) */ | |
| 259 | − ad9389b_csc_rgb_full2limit(sd, false); | |
| 260 | − break; | |
| 261 | − default: | |
| 262 | − return -EINVAL; | |
| 263 | − } | |
| 264 | − return 0; | |
| 265 | −} | |
| 266 | − | |
| 267 | −static void ad9389b_set_manual_pll_gear(struct v4l2_subdev *sd, u32 pixelclock) | |
| 268 | −{ | |
| 269 | − u8 gear; | |
| 270 | − | |
| 271 | − /* Workaround for TMDS PLL problem | |
| 272 | − * The TMDS PLL in AD9389b change gear when the chip is heated above a | |
| 273 | − * certain temperature. The output is disabled when the PLL change gear | |
| 274 | − * so the monitor has to lock on the signal again. A workaround for | |
| 275 | − * this is to use the manual PLL gears. This is a solution from Analog | |
| 276 | − * Devices that is not documented in the datasheets. | |
| 277 | − * 0x98 [7] = enable manual gearing. 0x98 [6:4] = gear | |
| 278 | − * | |
| 279 | − * The pixel frequency ranges are based on readout of the gear the | |
| 280 | − * automatic gearing selects for different pixel clocks | |
| 281 | − * (read from 0x9e [3:1]). | |
| 282 | − */ | |
| 283 | − | |
| 284 | − if (pixelclock > 140000000) | |
| 285 | − gear = 0xc0; /* 4th gear */ | |
| 286 | − else if (pixelclock > 117000000) | |
| 287 | − gear = 0xb0; /* 3rd gear */ | |
| 288 | − else if (pixelclock > 87000000) | |
| 289 | − gear = 0xa0; /* 2nd gear */ | |
| 290 | − else if (pixelclock > 60000000) | |
| 291 | − gear = 0x90; /* 1st gear */ | |
| 292 | − else | |
| 293 | − gear = 0x80; /* 0th gear */ | |
| 294 | − | |
| 295 | − ad9389b_wr_and_or(sd, 0x98, 0x0f, gear); | |
| 296 | −} | |
| 297 | − | |
| 298 | −/* ------------------------------ CTRL OPS ------------------------------ */ | |
| 299 | − | |
| 300 | −static int ad9389b_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 301 | −{ | |
| 302 | − struct v4l2_subdev *sd = to_sd(ctrl); | |
| 303 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 304 | − | |
| 305 | − v4l2_dbg(1, debug, sd, | |
| 306 | − "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val); | |
| 307 | − | |
| 308 | − if (state->hdmi_mode_ctrl == ctrl) { | |
| 309 | − /* Set HDMI or DVI-D */ | |
| 310 | − ad9389b_wr_and_or(sd, 0xaf, 0xfd, | |
| 311 | − ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); | |
| 312 | − return 0; | |
| 313 | − } | |
| 314 | − if (state->rgb_quantization_range_ctrl == ctrl) | |
| 315 | − return ad9389b_set_rgb_quantization_mode(sd, ctrl); | |
| 316 | − return -EINVAL; | |
| 317 | −} | |
| 318 | − | |
| 319 | −static const struct v4l2_ctrl_ops ad9389b_ctrl_ops = { | |
| 320 | − .s_ctrl = ad9389b_s_ctrl, | |
| 321 | −}; | |
| 322 | − | |
| 323 | −/* ---------------------------- CORE OPS ------------------------------------------- */ | |
| 324 | − | |
| 325 | −#ifdef CONFIG_VIDEO_ADV_DEBUG | |
| 326 | −static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | |
| 327 | −{ | |
| 328 | − reg->val = ad9389b_rd(sd, reg->reg & 0xff); | |
| 329 | − reg->size = 1; | |
| 330 | − return 0; | |
| 331 | −} | |
| 332 | − | |
| 333 | −static int ad9389b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) | |
| 334 | −{ | |
| 335 | − ad9389b_wr(sd, reg->reg & 0xff, reg->val & 0xff); | |
| 336 | − return 0; | |
| 337 | −} | |
| 338 | −#endif | |
| 339 | − | |
| 340 | −static int ad9389b_log_status(struct v4l2_subdev *sd) | |
| 341 | −{ | |
| 342 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 343 | − struct ad9389b_state_edid *edid = &state->edid; | |
| 344 | − | |
| 345 | − static const char * const states[] = { | |
| 346 | − "in reset", | |
| 347 | − "reading EDID", | |
| 348 | − "idle", | |
| 349 | − "initializing HDCP", | |
| 350 | − "HDCP enabled", | |
| 351 | − "initializing HDCP repeater", | |
| 352 | − "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" | |
| 353 | − }; | |
| 354 | − static const char * const errors[] = { | |
| 355 | − "no error", | |
| 356 | − "bad receiver BKSV", | |
| 357 | − "Ri mismatch", | |
| 358 | − "Pj mismatch", | |
| 359 | − "i2c error", | |
| 360 | − "timed out", | |
| 361 | − "max repeater cascade exceeded", | |
| 362 | − "hash check failed", | |
| 363 | − "too many devices", | |
| 364 | − "9", "A", "B", "C", "D", "E", "F" | |
| 365 | − }; | |
| 366 | − | |
| 367 | − u8 manual_gear; | |
| 368 | − | |
| 369 | − v4l2_info(sd, "chip revision %d\n", state->chip_revision); | |
| 370 | − v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off"); | |
| 371 | − v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n", | |
| 372 | − (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ? | |
| 373 | − "detected" : "no", | |
| 374 | − (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ? | |
| 375 | − "detected" : "no", | |
| 376 | − edid->segments ? "found" : "no", edid->blocks); | |
| 377 | − v4l2_info(sd, "%s output %s\n", | |
| 378 | − (ad9389b_rd(sd, 0xaf) & 0x02) ? | |
| 379 | − "HDMI" : "DVI-D", | |
| 380 | − (ad9389b_rd(sd, 0xa1) & 0x3c) ? | |
| 381 | − "disabled" : "enabled"); | |
| 382 | − v4l2_info(sd, "ad9389b: %s\n", (ad9389b_rd(sd, 0xb8) & 0x40) ? | |
| 383 | − "encrypted" : "no encryption"); | |
| 384 | − v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n", | |
| 385 | − states[ad9389b_rd(sd, 0xc8) & 0xf], | |
| 386 | − errors[ad9389b_rd(sd, 0xc8) >> 4], | |
| 387 | − state->edid_detect_counter, | |
| 388 | − ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96)); | |
| 389 | − manual_gear = ad9389b_rd(sd, 0x98) & 0x80; | |
| 390 | − v4l2_info(sd, "ad9389b: RGB quantization: %s range\n", | |
| 391 | − ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full"); | |
| 392 | − v4l2_info(sd, "ad9389b: %s gear %d\n", | |
| 393 | − manual_gear ? "manual" : "automatic", | |
| 394 | − manual_gear ? ((ad9389b_rd(sd, 0x98) & 0x70) >> 4) : | |
| 395 | − ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1)); | |
| 396 | − if (ad9389b_rd(sd, 0xaf) & 0x02) { | |
| 397 | − /* HDMI only */ | |
| 398 | − u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80; | |
| 399 | − u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 | | |
| 400 | − ad9389b_rd(sd, 0x02) << 8 | | |
| 401 | − ad9389b_rd(sd, 0x03); | |
| 402 | − u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2; | |
| 403 | − u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f; | |
| 404 | − u32 CTS; | |
| 405 | − | |
| 406 | − if (manual_cts) | |
| 407 | − CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 | | |
| 408 | − ad9389b_rd(sd, 0x08) << 8 | | |
| 409 | − ad9389b_rd(sd, 0x09); | |
| 410 | − else | |
| 411 | − CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 | | |
| 412 | − ad9389b_rd(sd, 0x05) << 8 | | |
| 413 | − ad9389b_rd(sd, 0x06); | |
| 414 | − N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 | | |
| 415 | − ad9389b_rd(sd, 0x02) << 8 | | |
| 416 | − ad9389b_rd(sd, 0x03); | |
| 417 | − | |
| 418 | − v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n", | |
| 419 | − manual_cts ? "manual" : "automatic", N, CTS); | |
| 420 | − | |
| 421 | − v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n", | |
| 422 | − vic_detect, vic_sent); | |
| 423 | − } | |
| 424 | − if (state->dv_timings.type == V4L2_DV_BT_656_1120) | |
| 425 | − v4l2_print_dv_timings(sd->name, "timings: ", | |
| 426 | − &state->dv_timings, false); | |
| 427 | − else | |
| 428 | − v4l2_info(sd, "no timings set\n"); | |
| 429 | − return 0; | |
| 430 | −} | |
| 431 | − | |
| 432 | −/* Power up/down ad9389b */ | |
| 433 | −static int ad9389b_s_power(struct v4l2_subdev *sd, int on) | |
| 434 | −{ | |
| 435 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 436 | − struct ad9389b_platform_data *pdata = &state->pdata; | |
| 437 | − const int retries = 20; | |
| 438 | − int i; | |
| 439 | − | |
| 440 | − v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off"); | |
| 441 | − | |
| 442 | − state->power_on = on; | |
| 443 | − | |
| 444 | − if (!on) { | |
| 445 | − /* Power down */ | |
| 446 | − ad9389b_wr_and_or(sd, 0x41, 0xbf, 0x40); | |
| 447 | − return true; | |
| 448 | − } | |
| 449 | − | |
| 450 | − /* Power up */ | |
| 451 | − /* The ad9389b does not always come up immediately. | |
| 452 | − Retry multiple times. */ | |
| 453 | − for (i = 0; i < retries; i++) { | |
| 454 | − ad9389b_wr_and_or(sd, 0x41, 0xbf, 0x0); | |
| 455 | − if ((ad9389b_rd(sd, 0x41) & 0x40) == 0) | |
| 456 | − break; | |
| 457 | − ad9389b_wr_and_or(sd, 0x41, 0xbf, 0x40); | |
| 458 | − msleep(10); | |
| 459 | − } | |
| 460 | − if (i == retries) { | |
| 461 | − v4l2_dbg(1, debug, sd, "failed to powerup the ad9389b\n"); | |
| 462 | − ad9389b_s_power(sd, 0); | |
| 463 | − return false; | |
| 464 | − } | |
| 465 | − if (i > 1) | |
| 466 | − v4l2_dbg(1, debug, sd, | |
| 467 | − "needed %d retries to powerup the ad9389b\n", i); | |
| 468 | − | |
| 469 | − /* Select chip: AD9389B */ | |
| 470 | − ad9389b_wr_and_or(sd, 0xba, 0xef, 0x10); | |
| 471 | − | |
| 472 | − /* Reserved registers that must be set according to REF_01 p. 11*/ | |
| 473 | − ad9389b_wr_and_or(sd, 0x98, 0xf0, 0x07); | |
| 474 | − ad9389b_wr(sd, 0x9c, 0x38); | |
| 475 | − ad9389b_wr_and_or(sd, 0x9d, 0xfc, 0x01); | |
| 476 | − | |
| 477 | − /* Differential output drive strength */ | |
| 478 | − if (pdata->diff_data_drive_strength > 0) | |
| 479 | − ad9389b_wr(sd, 0xa2, pdata->diff_data_drive_strength); | |
| 480 | − else | |
| 481 | − ad9389b_wr(sd, 0xa2, 0x87); | |
| 482 | − | |
| 483 | − if (pdata->diff_clk_drive_strength > 0) | |
| 484 | − ad9389b_wr(sd, 0xa3, pdata->diff_clk_drive_strength); | |
| 485 | − else | |
| 486 | − ad9389b_wr(sd, 0xa3, 0x87); | |
| 487 | − | |
| 488 | − ad9389b_wr(sd, 0x0a, 0x01); | |
| 489 | − ad9389b_wr(sd, 0xbb, 0xff); | |
| 490 | − | |
| 491 | − /* Set number of attempts to read the EDID */ | |
| 492 | − ad9389b_wr(sd, 0xc9, 0xf); | |
| 493 | − return true; | |
| 494 | −} | |
| 495 | − | |
| 496 | −/* Enable interrupts */ | |
| 497 | −static void ad9389b_set_isr(struct v4l2_subdev *sd, bool enable) | |
| 498 | −{ | |
| 499 | − u8 irqs = MASK_AD9389B_HPD_INT | MASK_AD9389B_MSEN_INT; | |
| 500 | − u8 irqs_rd; | |
| 501 | − int retries = 100; | |
| 502 | − | |
| 503 | − /* The datasheet says that the EDID ready interrupt should be | |
| 504 | − disabled if there is no hotplug. */ | |
| 505 | − if (!enable) | |
| 506 | − irqs = 0; | |
| 507 | − else if (ad9389b_have_hotplug(sd)) | |
| 508 | − irqs |= MASK_AD9389B_EDID_RDY_INT; | |
| 509 | − | |
| 510 | − /* | |
| 511 | − * This i2c write can fail (approx. 1 in 1000 writes). But it | |
| 512 | − * is essential that this register is correct, so retry it | |
| 513 | − * multiple times. | |
| 514 | − * | |
| 515 | − * Note that the i2c write does not report an error, but the readback | |
| 516 | − * clearly shows the wrong value. | |
| 517 | − */ | |
| 518 | − do { | |
| 519 | − ad9389b_wr(sd, 0x94, irqs); | |
| 520 | − irqs_rd = ad9389b_rd(sd, 0x94); | |
| 521 | − } while (retries-- && irqs_rd != irqs); | |
| 522 | − | |
| 523 | − if (irqs_rd != irqs) | |
| 524 | − v4l2_err(sd, "Could not set interrupts: hw failure?\n"); | |
| 525 | −} | |
| 526 | − | |
| 527 | −/* Interrupt handler */ | |
| 528 | −static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | |
| 529 | −{ | |
| 530 | − u8 irq_status; | |
| 531 | − | |
| 532 | − /* disable interrupts to prevent a race condition */ | |
| 533 | − ad9389b_set_isr(sd, false); | |
| 534 | − irq_status = ad9389b_rd(sd, 0x96); | |
| 535 | − /* clear detected interrupts */ | |
| 536 | − ad9389b_wr(sd, 0x96, irq_status); | |
| 537 | − /* enable interrupts */ | |
| 538 | − ad9389b_set_isr(sd, true); | |
| 539 | − | |
| 540 | − v4l2_dbg(1, debug, sd, "%s: irq_status 0x%x\n", __func__, irq_status); | |
| 541 | − | |
| 542 | − if (irq_status & (MASK_AD9389B_HPD_INT)) | |
| 543 | − ad9389b_check_monitor_present_status(sd); | |
| 544 | − if (irq_status & MASK_AD9389B_EDID_RDY_INT) | |
| 545 | − ad9389b_check_edid_status(sd); | |
| 546 | − | |
| 547 | − *handled = true; | |
| 548 | − return 0; | |
| 549 | −} | |
| 550 | − | |
| 551 | −static const struct v4l2_subdev_core_ops ad9389b_core_ops = { | |
| 552 | − .log_status = ad9389b_log_status, | |
| 553 | −#ifdef CONFIG_VIDEO_ADV_DEBUG | |
| 554 | − .g_register = ad9389b_g_register, | |
| 555 | − .s_register = ad9389b_s_register, | |
| 556 | −#endif | |
| 557 | − .s_power = ad9389b_s_power, | |
| 558 | − .interrupt_service_routine = ad9389b_isr, | |
| 559 | −}; | |
| 560 | − | |
| 561 | −/* ------------------------------ VIDEO OPS ------------------------------ */ | |
| 562 | − | |
| 563 | −/* Enable/disable ad9389b output */ | |
| 564 | −static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable) | |
| 565 | −{ | |
| 566 | − v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); | |
| 567 | − | |
| 568 | − ad9389b_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c)); | |
| 569 | − if (enable) { | |
| 570 | − ad9389b_check_monitor_present_status(sd); | |
| 571 | − } else { | |
| 572 | − ad9389b_s_power(sd, 0); | |
| 573 | − } | |
| 574 | − return 0; | |
| 575 | −} | |
| 576 | − | |
| 577 | −static const struct v4l2_dv_timings_cap ad9389b_timings_cap = { | |
| 578 | − .type = V4L2_DV_BT_656_1120, | |
| 579 | − /* keep this initialization for compatibility with GCC < 4.4.6 */ | |
| 580 | − .reserved = { 0 }, | |
| 581 | − V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000, | |
| 582 | − V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | | |
| 583 | − V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, | |
| 584 | − V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING | | |
| 585 | − V4L2_DV_BT_CAP_CUSTOM) | |
| 586 | −}; | |
| 587 | − | |
| 588 | −static int ad9389b_s_dv_timings(struct v4l2_subdev *sd, | |
| 589 | − struct v4l2_dv_timings *timings) | |
| 590 | −{ | |
| 591 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 592 | − | |
| 593 | − v4l2_dbg(1, debug, sd, "%s:\n", __func__); | |
| 594 | − | |
| 595 | − /* quick sanity check */ | |
| 596 | − if (!v4l2_valid_dv_timings(timings, &ad9389b_timings_cap, NULL, NULL)) | |
| 597 | − return -EINVAL; | |
| 598 | − | |
| 599 | − /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings | |
| 600 | − if the format is one of the CEA or DMT timings. */ | |
| 601 | − v4l2_find_dv_timings_cap(timings, &ad9389b_timings_cap, 0, NULL, NULL); | |
| 602 | − | |
| 603 | − timings->bt.flags &= ~V4L2_DV_FL_REDUCED_FPS; | |
| 604 | − | |
| 605 | − /* save timings */ | |
| 606 | − state->dv_timings = *timings; | |
| 607 | − | |
| 608 | − /* update quantization range based on new dv_timings */ | |
| 609 | − ad9389b_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); | |
| 610 | − | |
| 611 | − /* update PLL gear based on new dv_timings */ | |
| 612 | − if (state->pdata.tmds_pll_gear == AD9389B_TMDS_PLL_GEAR_SEMI_AUTOMATIC) | |
| 613 | − ad9389b_set_manual_pll_gear(sd, (u32)timings->bt.pixelclock); | |
| 614 | − | |
| 615 | − /* update AVI infoframe */ | |
| 616 | − ad9389b_set_IT_content_AVI_InfoFrame(sd); | |
| 617 | − | |
| 618 | − return 0; | |
| 619 | −} | |
| 620 | − | |
| 621 | −static int ad9389b_g_dv_timings(struct v4l2_subdev *sd, | |
| 622 | − struct v4l2_dv_timings *timings) | |
| 623 | −{ | |
| 624 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 625 | − | |
| 626 | − v4l2_dbg(1, debug, sd, "%s:\n", __func__); | |
| 627 | − | |
| 628 | − if (!timings) | |
| 629 | − return -EINVAL; | |
| 630 | − | |
| 631 | − *timings = state->dv_timings; | |
| 632 | − | |
| 633 | − return 0; | |
| 634 | −} | |
| 635 | − | |
| 636 | −static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd, | |
| 637 | − struct v4l2_enum_dv_timings *timings) | |
| 638 | −{ | |
| 639 | − if (timings->pad != 0) | |
| 640 | − return -EINVAL; | |
| 641 | − | |
| 642 | − return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap, | |
| 643 | − NULL, NULL); | |
| 644 | −} | |
| 645 | − | |
| 646 | −static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd, | |
| 647 | − struct v4l2_dv_timings_cap *cap) | |
| 648 | −{ | |
| 649 | − if (cap->pad != 0) | |
| 650 | − return -EINVAL; | |
| 651 | − | |
| 652 | − *cap = ad9389b_timings_cap; | |
| 653 | − return 0; | |
| 654 | −} | |
| 655 | − | |
| 656 | −static const struct v4l2_subdev_video_ops ad9389b_video_ops = { | |
| 657 | − .s_stream = ad9389b_s_stream, | |
| 658 | − .s_dv_timings = ad9389b_s_dv_timings, | |
| 659 | − .g_dv_timings = ad9389b_g_dv_timings, | |
| 660 | −}; | |
| 661 | − | |
| 662 | −/* ------------------------------ PAD OPS ------------------------------ */ | |
| 663 | − | |
| 664 | −static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | |
| 665 | −{ | |
| 666 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 667 | − | |
| 668 | − if (edid->pad != 0) | |
| 669 | − return -EINVAL; | |
| 670 | − if (edid->blocks == 0 || edid->blocks > 256) | |
| 671 | − return -EINVAL; | |
| 672 | − if (!state->edid.segments) { | |
| 673 | − v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n"); | |
| 674 | − return -ENODATA; | |
| 675 | − } | |
| 676 | − if (edid->start_block >= state->edid.segments * 2) | |
| 677 | − return -E2BIG; | |
| 678 | − if (edid->blocks + edid->start_block >= state->edid.segments * 2) | |
| 679 | − edid->blocks = state->edid.segments * 2 - edid->start_block; | |
| 680 | − memcpy(edid->edid, &state->edid.data[edid->start_block * 128], | |
| 681 | − 128 * edid->blocks); | |
| 682 | − return 0; | |
| 683 | −} | |
| 684 | − | |
| 685 | −static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = { | |
| 686 | − .get_edid = ad9389b_get_edid, | |
| 687 | − .enum_dv_timings = ad9389b_enum_dv_timings, | |
| 688 | − .dv_timings_cap = ad9389b_dv_timings_cap, | |
| 689 | −}; | |
| 690 | − | |
| 691 | −/* ------------------------------ AUDIO OPS ------------------------------ */ | |
| 692 | − | |
| 693 | −static int ad9389b_s_audio_stream(struct v4l2_subdev *sd, int enable) | |
| 694 | −{ | |
| 695 | − v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); | |
| 696 | − | |
| 697 | − if (enable) | |
| 698 | − ad9389b_wr_and_or(sd, 0x45, 0x3f, 0x80); | |
| 699 | − else | |
| 700 | − ad9389b_wr_and_or(sd, 0x45, 0x3f, 0x40); | |
| 701 | − | |
| 702 | − return 0; | |
| 703 | −} | |
| 704 | − | |
| 705 | −static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |
| 706 | −{ | |
| 707 | − u32 N; | |
| 708 | − | |
| 709 | − switch (freq) { | |
| 710 | − case 32000: N = 4096; break; | |
| 711 | − case 44100: N = 6272; break; | |
| 712 | − case 48000: N = 6144; break; | |
| 713 | − case 88200: N = 12544; break; | |
| 714 | − case 96000: N = 12288; break; | |
| 715 | − case 176400: N = 25088; break; | |
| 716 | − case 192000: N = 24576; break; | |
| 717 | − default: | |
| 718 | − return -EINVAL; | |
| 719 | − } | |
| 720 | − | |
| 721 | − /* Set N (used with CTS to regenerate the audio clock) */ | |
| 722 | − ad9389b_wr(sd, 0x01, (N >> 16) & 0xf); | |
| 723 | − ad9389b_wr(sd, 0x02, (N >> 8) & 0xff); | |
| 724 | − ad9389b_wr(sd, 0x03, N & 0xff); | |
| 725 | − | |
| 726 | − return 0; | |
| 727 | −} | |
| 728 | − | |
| 729 | −static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |
| 730 | −{ | |
| 731 | − u32 i2s_sf; | |
| 732 | − | |
| 733 | − switch (freq) { | |
| 734 | − case 32000: i2s_sf = 0x30; break; | |
| 735 | − case 44100: i2s_sf = 0x00; break; | |
| 736 | − case 48000: i2s_sf = 0x20; break; | |
| 737 | − case 88200: i2s_sf = 0x80; break; | |
| 738 | − case 96000: i2s_sf = 0xa0; break; | |
| 739 | − case 176400: i2s_sf = 0xc0; break; | |
| 740 | − case 192000: i2s_sf = 0xe0; break; | |
| 741 | − default: | |
| 742 | − return -EINVAL; | |
| 743 | − } | |
| 744 | − | |
| 745 | − /* Set sampling frequency for I2S audio to 48 kHz */ | |
| 746 | − ad9389b_wr_and_or(sd, 0x15, 0xf, i2s_sf); | |
| 747 | − | |
| 748 | − return 0; | |
| 749 | −} | |
| 750 | − | |
| 751 | −static int ad9389b_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config) | |
| 752 | −{ | |
| 753 | − /* TODO based on input/output/config */ | |
| 754 | − /* TODO See datasheet "Programmers guide" p. 39-40 */ | |
| 755 | − | |
| 756 | − /* Only 2 channels in use for application */ | |
| 757 | − ad9389b_wr_and_or(sd, 0x50, 0x1f, 0x20); | |
| 758 | − /* Speaker mapping */ | |
| 759 | − ad9389b_wr(sd, 0x51, 0x00); | |
| 760 | − | |
| 761 | − /* TODO Where should this be placed? */ | |
| 762 | − /* 16 bit audio word length */ | |
| 763 | − ad9389b_wr_and_or(sd, 0x14, 0xf0, 0x02); | |
| 764 | − | |
| 765 | − return 0; | |
| 766 | −} | |
| 767 | − | |
| 768 | −static const struct v4l2_subdev_audio_ops ad9389b_audio_ops = { | |
| 769 | − .s_stream = ad9389b_s_audio_stream, | |
| 770 | − .s_clock_freq = ad9389b_s_clock_freq, | |
| 771 | − .s_i2s_clock_freq = ad9389b_s_i2s_clock_freq, | |
| 772 | − .s_routing = ad9389b_s_routing, | |
| 773 | −}; | |
| 774 | − | |
| 775 | −/* --------------------- SUBDEV OPS --------------------------------------- */ | |
| 776 | − | |
| 777 | −static const struct v4l2_subdev_ops ad9389b_ops = { | |
| 778 | − .core = &ad9389b_core_ops, | |
| 779 | − .video = &ad9389b_video_ops, | |
| 780 | − .audio = &ad9389b_audio_ops, | |
| 781 | − .pad = &ad9389b_pad_ops, | |
| 782 | −}; | |
| 783 | − | |
| 784 | −/* ----------------------------------------------------------------------- */ | |
| 785 | −static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, | |
| 786 | − int segment, u8 *buf) | |
| 787 | −{ | |
| 788 | − int i, j; | |
| 789 | − | |
| 790 | − if (debug < lvl) | |
| 791 | − return; | |
| 792 | − | |
| 793 | − v4l2_dbg(lvl, debug, sd, "edid segment %d\n", segment); | |
| 794 | − for (i = 0; i < 256; i += 16) { | |
| 795 | − u8 b[128]; | |
| 796 | − u8 *bp = b; | |
| 797 | − | |
| 798 | − if (i == 128) | |
| 799 | − v4l2_dbg(lvl, debug, sd, "\n"); | |
| 800 | − for (j = i; j < i + 16; j++) { | |
| 801 | − sprintf(bp, "0x%02x, ", buf[j]); | |
| 802 | − bp += 6; | |
| 803 | − } | |
| 804 | − bp[0] = '\0'; | |
| 805 | − v4l2_dbg(lvl, debug, sd, "%s\n", b); | |
| 806 | − } | |
| 807 | −} | |
| 808 | − | |
| 809 | −static void ad9389b_edid_handler(struct work_struct *work) | |
| 810 | −{ | |
| 811 | − struct delayed_work *dwork = to_delayed_work(work); | |
| 812 | − struct ad9389b_state *state = | |
| 813 | − container_of(dwork, struct ad9389b_state, edid_handler); | |
| 814 | − struct v4l2_subdev *sd = &state->sd; | |
| 815 | − struct ad9389b_edid_detect ed; | |
| 816 | − | |
| 817 | − v4l2_dbg(1, debug, sd, "%s:\n", __func__); | |
| 818 | − | |
| 819 | − if (ad9389b_check_edid_status(sd)) { | |
| 820 | − /* Return if we received the EDID. */ | |
| 821 | − return; | |
| 822 | − } | |
| 823 | − | |
| 824 | − if (ad9389b_have_hotplug(sd)) { | |
| 825 | − /* We must retry reading the EDID several times, it is possible | |
| 826 | − * that initially the EDID couldn't be read due to i2c errors | |
| 827 | − * (DVI connectors are particularly prone to this problem). */ | |
| 828 | − if (state->edid.read_retries) { | |
| 829 | − state->edid.read_retries--; | |
| 830 | − v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__); | |
| 831 | − ad9389b_s_power(sd, false); | |
| 832 | − ad9389b_s_power(sd, true); | |
| 833 | − schedule_delayed_work(&state->edid_handler, EDID_DELAY); | |
| 834 | − return; | |
| 835 | − } | |
| 836 | − } | |
| 837 | − | |
| 838 | − /* We failed to read the EDID, so send an event for this. */ | |
| 839 | − ed.present = false; | |
| 840 | − ed.segment = ad9389b_rd(sd, 0xc4); | |
| 841 | − v4l2_subdev_notify(sd, AD9389B_EDID_DETECT, (void *)&ed); | |
| 842 | − v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__); | |
| 843 | −} | |
| 844 | − | |
| 845 | −static void ad9389b_audio_setup(struct v4l2_subdev *sd) | |
| 846 | −{ | |
| 847 | − v4l2_dbg(1, debug, sd, "%s\n", __func__); | |
| 848 | − | |
| 849 | − ad9389b_s_i2s_clock_freq(sd, 48000); | |
| 850 | − ad9389b_s_clock_freq(sd, 48000); | |
| 851 | − ad9389b_s_routing(sd, 0, 0, 0); | |
| 852 | −} | |
| 853 | − | |
| 854 | −/* Initial setup of AD9389b */ | |
| 855 | − | |
| 856 | −/* Configure hdmi transmitter. */ | |
| 857 | −static void ad9389b_setup(struct v4l2_subdev *sd) | |
| 858 | −{ | |
| 859 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 860 | − | |
| 861 | − v4l2_dbg(1, debug, sd, "%s\n", __func__); | |
| 862 | − | |
| 863 | − /* Input format: RGB 4:4:4 */ | |
| 864 | − ad9389b_wr_and_or(sd, 0x15, 0xf1, 0x0); | |
| 865 | − /* Output format: RGB 4:4:4 */ | |
| 866 | − ad9389b_wr_and_or(sd, 0x16, 0x3f, 0x0); | |
| 867 | − /* 1st order interpolation 4:2:2 -> 4:4:4 up conversion, | |
| 868 | − Aspect ratio: 16:9 */ | |
| 869 | − ad9389b_wr_and_or(sd, 0x17, 0xf9, 0x06); | |
| 870 | − /* Output format: RGB 4:4:4, Active Format Information is valid. */ | |
| 871 | − ad9389b_wr_and_or(sd, 0x45, 0xc7, 0x08); | |
| 872 | − /* Underscanned */ | |
| 873 | − ad9389b_wr_and_or(sd, 0x46, 0x3f, 0x80); | |
| 874 | − /* Setup video format */ | |
| 875 | − ad9389b_wr(sd, 0x3c, 0x0); | |
| 876 | − /* Active format aspect ratio: same as picure. */ | |
| 877 | − ad9389b_wr(sd, 0x47, 0x80); | |
| 878 | − /* No encryption */ | |
| 879 | − ad9389b_wr_and_or(sd, 0xaf, 0xef, 0x0); | |
| 880 | − /* Positive clk edge capture for input video clock */ | |
| 881 | − ad9389b_wr_and_or(sd, 0xba, 0x1f, 0x60); | |
| 882 | − | |
| 883 | − ad9389b_audio_setup(sd); | |
| 884 | − | |
| 885 | − v4l2_ctrl_handler_setup(&state->hdl); | |
| 886 | − | |
| 887 | − ad9389b_set_IT_content_AVI_InfoFrame(sd); | |
| 888 | −} | |
| 889 | − | |
| 890 | −static void ad9389b_notify_monitor_detect(struct v4l2_subdev *sd) | |
| 891 | −{ | |
| 892 | − struct ad9389b_monitor_detect mdt; | |
| 893 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 894 | − | |
| 895 | − mdt.present = state->have_monitor; | |
| 896 | − v4l2_subdev_notify(sd, AD9389B_MONITOR_DETECT, (void *)&mdt); | |
| 897 | −} | |
| 898 | − | |
| 899 | −static void ad9389b_update_monitor_present_status(struct v4l2_subdev *sd) | |
| 900 | −{ | |
| 901 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 902 | − /* read hotplug and rx-sense state */ | |
| 903 | − u8 status = ad9389b_rd(sd, 0x42); | |
| 904 | − | |
| 905 | − v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n", | |
| 906 | − __func__, | |
| 907 | − status, | |
| 908 | − status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "", | |
| 909 | − status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : ""); | |
| 910 | − | |
| 911 | − if (status & MASK_AD9389B_HPD_DETECT) { | |
| 912 | − v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__); | |
| 913 | − state->have_monitor = true; | |
| 914 | − if (!ad9389b_s_power(sd, true)) { | |
| 915 | − v4l2_dbg(1, debug, sd, | |
| 916 | − "%s: monitor detected, powerup failed\n", __func__); | |
| 917 | − return; | |
| 918 | − } | |
| 919 | − ad9389b_setup(sd); | |
| 920 | − ad9389b_notify_monitor_detect(sd); | |
| 921 | − state->edid.read_retries = EDID_MAX_RETRIES; | |
| 922 | − schedule_delayed_work(&state->edid_handler, EDID_DELAY); | |
| 923 | − } else if (!(status & MASK_AD9389B_HPD_DETECT)) { | |
| 924 | − v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__); | |
| 925 | − state->have_monitor = false; | |
| 926 | − ad9389b_notify_monitor_detect(sd); | |
| 927 | − ad9389b_s_power(sd, false); | |
| 928 | − memset(&state->edid, 0, sizeof(struct ad9389b_state_edid)); | |
| 929 | − } | |
| 930 | − | |
| 931 | − /* update read only ctrls */ | |
| 932 | − v4l2_ctrl_s_ctrl(state->hotplug_ctrl, ad9389b_have_hotplug(sd) ? 0x1 : 0x0); | |
| 933 | − v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, ad9389b_have_rx_sense(sd) ? 0x1 : 0x0); | |
| 934 | − v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0); | |
| 935 | − | |
| 936 | − /* update with setting from ctrls */ | |
| 937 | − ad9389b_s_ctrl(state->rgb_quantization_range_ctrl); | |
| 938 | − ad9389b_s_ctrl(state->hdmi_mode_ctrl); | |
| 939 | −} | |
| 940 | − | |
| 941 | −static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd) | |
| 942 | −{ | |
| 943 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 944 | − int retry = 0; | |
| 945 | − | |
| 946 | − ad9389b_update_monitor_present_status(sd); | |
| 947 | − | |
| 948 | − /* | |
| 949 | − * Rapid toggling of the hotplug may leave the chip powered off, | |
| 950 | − * even if we think it is on. In that case reset and power up again. | |
| 951 | − */ | |
| 952 | − while (state->power_on && (ad9389b_rd(sd, 0x41) & 0x40)) { | |
| 953 | − if (++retry > 5) { | |
| 954 | − v4l2_err(sd, "retried %d times, give up\n", retry); | |
| 955 | − return; | |
| 956 | − } | |
| 957 | − v4l2_dbg(1, debug, sd, "%s: reset and re-check status (%d)\n", __func__, retry); | |
| 958 | − ad9389b_notify_monitor_detect(sd); | |
| 959 | − cancel_delayed_work_sync(&state->edid_handler); | |
| 960 | − memset(&state->edid, 0, sizeof(struct ad9389b_state_edid)); | |
| 961 | − ad9389b_s_power(sd, false); | |
| 962 | − ad9389b_update_monitor_present_status(sd); | |
| 963 | − } | |
| 964 | −} | |
| 965 | − | |
| 966 | −static bool edid_block_verify_crc(u8 *edid_block) | |
| 967 | −{ | |
| 968 | − u8 sum = 0; | |
| 969 | − int i; | |
| 970 | − | |
| 971 | − for (i = 0; i < 128; i++) | |
| 972 | − sum += edid_block[i]; | |
| 973 | − return sum == 0; | |
| 974 | −} | |
| 975 | − | |
| 976 | −static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment) | |
| 977 | −{ | |
| 978 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 979 | − u32 blocks = state->edid.blocks; | |
| 980 | − u8 *data = state->edid.data; | |
| 981 | − | |
| 982 | − if (edid_block_verify_crc(&data[segment * 256])) { | |
| 983 | − if ((segment + 1) * 2 <= blocks) | |
| 984 | − return edid_block_verify_crc(&data[segment * 256 + 128]); | |
| 985 | − return true; | |
| 986 | − } | |
| 987 | − return false; | |
| 988 | −} | |
| 989 | − | |
| 990 | −static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment) | |
| 991 | −{ | |
| 992 | − static const u8 hdmi_header[] = { | |
| 993 | − 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 | |
| 994 | − }; | |
| 995 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 996 | − u8 *data = state->edid.data; | |
| 997 | − int i; | |
| 998 | − | |
| 999 | − if (segment) | |
| 1000 | − return true; | |
| 1001 | − | |
| 1002 | − for (i = 0; i < ARRAY_SIZE(hdmi_header); i++) | |
| 1003 | − if (data[i] != hdmi_header[i]) | |
| 1004 | − return false; | |
| 1005 | − | |
| 1006 | − return true; | |
| 1007 | −} | |
| 1008 | − | |
| 1009 | −static bool ad9389b_check_edid_status(struct v4l2_subdev *sd) | |
| 1010 | −{ | |
| 1011 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 1012 | − struct ad9389b_edid_detect ed; | |
| 1013 | − int segment; | |
| 1014 | − u8 edidRdy = ad9389b_rd(sd, 0xc5); | |
| 1015 | − | |
| 1016 | − v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n", | |
| 1017 | − __func__, EDID_MAX_RETRIES - state->edid.read_retries); | |
| 1018 | − | |
| 1019 | − if (!(edidRdy & MASK_AD9389B_EDID_RDY)) | |
| 1020 | − return false; | |
| 1021 | − | |
| 1022 | − segment = ad9389b_rd(sd, 0xc4); | |
| 1023 | − if (segment >= EDID_MAX_SEGM) { | |
| 1024 | − v4l2_err(sd, "edid segment number too big\n"); | |
| 1025 | − return false; | |
| 1026 | − } | |
| 1027 | − v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment); | |
| 1028 | − ad9389b_edid_rd(sd, 256, &state->edid.data[segment * 256]); | |
| 1029 | − ad9389b_dbg_dump_edid(2, debug, sd, segment, | |
| 1030 | − &state->edid.data[segment * 256]); | |
| 1031 | − if (segment == 0) { | |
| 1032 | − state->edid.blocks = state->edid.data[0x7e] + 1; | |
| 1033 | − v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", | |
| 1034 | − __func__, state->edid.blocks); | |
| 1035 | − } | |
| 1036 | − if (!edid_verify_crc(sd, segment) || | |
| 1037 | − !edid_verify_header(sd, segment)) { | |
| 1038 | − /* edid crc error, force reread of edid segment */ | |
| 1039 | − v4l2_err(sd, "%s: edid crc or header error\n", __func__); | |
| 1040 | − ad9389b_s_power(sd, false); | |
| 1041 | − ad9389b_s_power(sd, true); | |
| 1042 | − return false; | |
| 1043 | − } | |
| 1044 | − /* one more segment read ok */ | |
| 1045 | − state->edid.segments = segment + 1; | |
| 1046 | − if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) { | |
| 1047 | − /* Request next EDID segment */ | |
| 1048 | − v4l2_dbg(1, debug, sd, "%s: request segment %d\n", | |
| 1049 | − __func__, state->edid.segments); | |
| 1050 | − ad9389b_wr(sd, 0xc9, 0xf); | |
| 1051 | − ad9389b_wr(sd, 0xc4, state->edid.segments); | |
| 1052 | − state->edid.read_retries = EDID_MAX_RETRIES; | |
| 1053 | − schedule_delayed_work(&state->edid_handler, EDID_DELAY); | |
| 1054 | − return false; | |
| 1055 | − } | |
| 1056 | − | |
| 1057 | − /* report when we have all segments but report only for segment 0 */ | |
| 1058 | − ed.present = true; | |
| 1059 | − ed.segment = 0; | |
| 1060 | − v4l2_subdev_notify(sd, AD9389B_EDID_DETECT, (void *)&ed); | |
| 1061 | − state->edid_detect_counter++; | |
| 1062 | − v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0); | |
| 1063 | − return ed.present; | |
| 1064 | −} | |
| 1065 | − | |
| 1066 | −/* ----------------------------------------------------------------------- */ | |
| 1067 | − | |
| 1068 | −static void ad9389b_init_setup(struct v4l2_subdev *sd) | |
| 1069 | −{ | |
| 1070 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 1071 | − struct ad9389b_state_edid *edid = &state->edid; | |
| 1072 | − | |
| 1073 | − v4l2_dbg(1, debug, sd, "%s\n", __func__); | |
| 1074 | − | |
| 1075 | − /* clear all interrupts */ | |
| 1076 | − ad9389b_wr(sd, 0x96, 0xff); | |
| 1077 | − | |
| 1078 | − memset(edid, 0, sizeof(struct ad9389b_state_edid)); | |
| 1079 | − state->have_monitor = false; | |
| 1080 | − ad9389b_set_isr(sd, false); | |
| 1081 | −} | |
| 1082 | − | |
| 1083 | −static int ad9389b_probe(struct i2c_client *client) | |
| 1084 | −{ | |
| 1085 | − const struct v4l2_dv_timings dv1080p60 = V4L2_DV_BT_CEA_1920X1080P60; | |
| 1086 | − struct ad9389b_state *state; | |
| 1087 | − struct ad9389b_platform_data *pdata = client->dev.platform_data; | |
| 1088 | − struct v4l2_ctrl_handler *hdl; | |
| 1089 | − struct v4l2_subdev *sd; | |
| 1090 | − int err = -EIO; | |
| 1091 | − | |
| 1092 | − /* Check if the adapter supports the needed features */ | |
| 1093 | − if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
| 1094 | − return -EIO; | |
| 1095 | − | |
| 1096 | − v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n", | |
| 1097 | − client->addr << 1); | |
| 1098 | − | |
| 1099 | − state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); | |
| 1100 | − if (!state) | |
| 1101 | − return -ENOMEM; | |
| 1102 | − | |
| 1103 | − /* Platform data */ | |
| 1104 | − if (pdata == NULL) { | |
| 1105 | − v4l_err(client, "No platform data!\n"); | |
| 1106 | − return -ENODEV; | |
| 1107 | − } | |
| 1108 | − memcpy(&state->pdata, pdata, sizeof(state->pdata)); | |
| 1109 | − | |
| 1110 | − sd = &state->sd; | |
| 1111 | − v4l2_i2c_subdev_init(sd, client, &ad9389b_ops); | |
| 1112 | − sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1113 | − | |
| 1114 | − hdl = &state->hdl; | |
| 1115 | − v4l2_ctrl_handler_init(hdl, 5); | |
| 1116 | − | |
| 1117 | − state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops, | |
| 1118 | − V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, | |
| 1119 | − 0, V4L2_DV_TX_MODE_DVI_D); | |
| 1120 | − state->hotplug_ctrl = v4l2_ctrl_new_std(hdl, NULL, | |
| 1121 | − V4L2_CID_DV_TX_HOTPLUG, 0, 1, 0, 0); | |
| 1122 | − state->rx_sense_ctrl = v4l2_ctrl_new_std(hdl, NULL, | |
| 1123 | − V4L2_CID_DV_TX_RXSENSE, 0, 1, 0, 0); | |
| 1124 | − state->have_edid0_ctrl = v4l2_ctrl_new_std(hdl, NULL, | |
| 1125 | − V4L2_CID_DV_TX_EDID_PRESENT, 0, 1, 0, 0); | |
| 1126 | − state->rgb_quantization_range_ctrl = | |
| 1127 | − v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops, | |
| 1128 | − V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, | |
| 1129 | − 0, V4L2_DV_RGB_RANGE_AUTO); | |
| 1130 | − sd->ctrl_handler = hdl; | |
| 1131 | − if (hdl->error) { | |
| 1132 | − err = hdl->error; | |
| 1133 | − | |
| 1134 | − goto err_hdl; | |
| 1135 | − } | |
| 1136 | − state->pad.flags = MEDIA_PAD_FL_SINK; | |
| 1137 | − sd->entity.function = MEDIA_ENT_F_DV_ENCODER; | |
| 1138 | − err = media_entity_pads_init(&sd->entity, 1, &state->pad); | |
| 1139 | − if (err) | |
| 1140 | − goto err_hdl; | |
| 1141 | − | |
| 1142 | − state->chip_revision = ad9389b_rd(sd, 0x0); | |
| 1143 | − if (state->chip_revision != 2) { | |
| 1144 | − v4l2_err(sd, "chip_revision %d != 2\n", state->chip_revision); | |
| 1145 | − err = -EIO; | |
| 1146 | − goto err_entity; | |
| 1147 | − } | |
| 1148 | − v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n", | |
| 1149 | − ad9389b_rd(sd, 0x41), state->chip_revision); | |
| 1150 | − | |
| 1151 | − state->edid_i2c_client = i2c_new_dummy_device(client->adapter, (0x7e >> 1)); | |
| 1152 | − if (IS_ERR(state->edid_i2c_client)) { | |
| 1153 | − v4l2_err(sd, "failed to register edid i2c client\n"); | |
| 1154 | − err = PTR_ERR(state->edid_i2c_client); | |
| 1155 | − goto err_entity; | |
| 1156 | − } | |
| 1157 | − | |
| 1158 | − INIT_DELAYED_WORK(&state->edid_handler, ad9389b_edid_handler); | |
| 1159 | − state->dv_timings = dv1080p60; | |
| 1160 | − | |
| 1161 | − ad9389b_init_setup(sd); | |
| 1162 | − ad9389b_set_isr(sd, true); | |
| 1163 | − | |
| 1164 | − v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, | |
| 1165 | − client->addr << 1, client->adapter->name); | |
| 1166 | − return 0; | |
| 1167 | − | |
| 1168 | −err_entity: | |
| 1169 | − media_entity_cleanup(&sd->entity); | |
| 1170 | −err_hdl: | |
| 1171 | − v4l2_ctrl_handler_free(&state->hdl); | |
| 1172 | − return err; | |
| 1173 | −} | |
| 1174 | − | |
| 1175 | −/* ----------------------------------------------------------------------- */ | |
| 1176 | − | |
| 1177 | −static void ad9389b_remove(struct i2c_client *client) | |
| 1178 | −{ | |
| 1179 | − struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1180 | − struct ad9389b_state *state = get_ad9389b_state(sd); | |
| 1181 | − | |
| 1182 | − state->chip_revision = -1; | |
| 1183 | − | |
| 1184 | − v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name, | |
| 1185 | − client->addr << 1, client->adapter->name); | |
| 1186 | − | |
| 1187 | − ad9389b_s_stream(sd, false); | |
| 1188 | − ad9389b_s_audio_stream(sd, false); | |
| 1189 | − ad9389b_init_setup(sd); | |
| 1190 | − cancel_delayed_work_sync(&state->edid_handler); | |
| 1191 | − i2c_unregister_device(state->edid_i2c_client); | |
| 1192 | − v4l2_device_unregister_subdev(sd); | |
| 1193 | − media_entity_cleanup(&sd->entity); | |
| 1194 | − v4l2_ctrl_handler_free(sd->ctrl_handler); | |
| 1195 | −} | |
| 1196 | − | |
| 1197 | −/* ----------------------------------------------------------------------- */ | |
| 1198 | − | |
| 1199 | −static const struct i2c_device_id ad9389b_id[] = { | |
| 1200 | − { "ad9389b", 0 }, | |
| 1201 | − { "ad9889b", 0 }, | |
| 1202 | − { } | |
| 1203 | −}; | |
| 1204 | −MODULE_DEVICE_TABLE(i2c, ad9389b_id); | |
| 1205 | − | |
| 1206 | −static struct i2c_driver ad9389b_driver = { | |
| 1207 | − .driver = { | |
| 1208 | − .name = "ad9389b", | |
| 1209 | − }, | |
| 1210 | − .probe_new = ad9389b_probe, | |
| 1211 | − .remove = ad9389b_remove, | |
| 1212 | − .id_table = ad9389b_id, | |
| 1213 | −}; | |
| 1214 | − | |
| 1215 | −module_i2c_driver(ad9389b_driver); | |
| @@ -176,9 +176,9 @@ static int adv748x_hdmi_set_video_timings(struct adv748x_state *state, · 175 unmodified lines | ||
| 176 | 176 | unsigned int i; |
| 177 | 177 | |
| 178 | 178 | for (i = 0; i < ARRAY_SIZE(adv748x_hdmi_video_standards); i++) { |
| 179 | − if (!v4l2_match_dv_timings(timings, &stds[i].timings, 250000, | |
| 180 | − false)) | |
| 181 | − continue; | |
| 179 | + if (v4l2_match_dv_timings(timings, &stds[i].timings, 250000, | |
| 180 | + false)) | |
| 181 | + break; | |
| 182 | 182 | } |
| 183 | 183 | |
| 184 | 184 | if (i >= ARRAY_SIZE(adv748x_hdmi_video_standards)) |
| @@ -283,6 +283,16 @@ static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd, · 98 unmodified lines | ||
| 283 | 283 | |
| 284 | 284 | memset(timings, 0, sizeof(struct v4l2_dv_timings)); |
| 285 | 285 | |
| 286 | + /* | |
| 287 | + * If the pattern generator is enabled the device shall not be queried | |
| 288 | + * for timings. Instead the timings programmed shall be reported as they | |
| 289 | + * are the ones being used to generate the pattern. | |
| 290 | + */ | |
| 291 | + if (cp_read(state, ADV748X_CP_PAT_GEN) & ADV748X_CP_PAT_GEN_EN) { | |
| 292 | + *timings = hdmi->timings; | |
| 293 | + return 0; | |
| 294 | + } | |
| 295 | + | |
| 286 | 296 | if (!adv748x_hdmi_has_signal(state)) |
| 287 | 297 | return -ENOLINK; |
| 288 | 298 | |
| @@ -721,11 +731,10 @@ static int adv748x_hdmi_init_controls(struct adv748x_hdmi *hdmi) · 432 unmodified lines | ||
| 721 | 731 | int adv748x_hdmi_init(struct adv748x_hdmi *hdmi) |
| 722 | 732 | { |
| 723 | 733 | struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); |
| 724 | − static const struct v4l2_dv_timings cea1280x720 = | |
| 725 | − V4L2_DV_BT_CEA_1280X720P30; | |
| 734 | + struct v4l2_dv_timings cea1280x720 = V4L2_DV_BT_CEA_1280X720P30; | |
| 726 | 735 | int ret; |
| 727 | 736 | |
| 728 | − hdmi->timings = cea1280x720; | |
| 737 | + adv748x_hdmi_s_dv_timings(&hdmi->sd, &cea1280x720); | |
| 729 | 738 | |
| 730 | 739 | /* Initialise a default 16:9 aspect ratio */ |
| 731 | 740 | hdmi->aspect_ratio.numerator = 16; |
| @@ -1805,6 +1805,9 @@ static void select_input(struct v4l2_subdev *sd) · 1804 unmodified lines | ||
| 1805 | 1805 | v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", |
| 1806 | 1806 | __func__, state->selected_input); |
| 1807 | 1807 | } |
| 1808 | + | |
| 1809 | + /* Enable video adjustment (contrast, saturation, brightness and hue) */ | |
| 1810 | + cp_write_clr_set(sd, 0x3e, 0x80, 0x80); | |
| 1808 | 1811 | } |
| 1809 | 1812 | |
| 1810 | 1813 | static int adv76xx_s_routing(struct v4l2_subdev *sd, |
| @@ -3545,7 +3548,7 @@ static int adv76xx_probe(struct i2c_client *client) · 1734 unmodified lines | ||
| 3545 | 3548 | v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, |
| 3546 | 3549 | V4L2_CID_SATURATION, 0, 255, 1, 128); |
| 3547 | 3550 | v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, |
| 3548 | − V4L2_CID_HUE, 0, 128, 1, 0); | |
| 3551 | + V4L2_CID_HUE, 0, 255, 1, 0); | |
| 3549 | 3552 | ctrl = v4l2_ctrl_new_std_menu(hdl, &adv76xx_ctrl_ops, |
| 3550 | 3553 | V4L2_CID_DV_RX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC, |
| 3551 | 3554 | 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); |
| @@ -569,8 +569,6 @@ static u32 ccs_pixel_order(struct ccs_sensor *sensor) · 568 unmodified lines | ||
| 569 | 569 | flip |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; |
| 570 | 570 | } |
| 571 | 571 | |
| 572 | − flip ^= sensor->hvflip_inv_mask; | |
| 573 | − | |
| 574 | 572 | dev_dbg(&client->dev, "flip %u\n", flip); |
| 575 | 573 | return sensor->default_pixel_order ^ flip; |
| 576 | 574 | } |
| @@ -632,8 +630,6 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) · 55 unmodified lines | ||
| 632 | 630 | if (sensor->vflip->val) |
| 633 | 631 | orient |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; |
| 634 | 632 | |
| 635 | − orient ^= sensor->hvflip_inv_mask; | |
| 636 | − | |
| 637 | 633 | ccs_update_mbus_formats(sensor); |
| 638 | 634 | |
| 639 | 635 | break; |
| @@ -800,14 +796,24 @@ static const struct v4l2_ctrl_ops ccs_ctrl_ops = { · 160 unmodified lines | ||
| 800 | 796 | static int ccs_init_controls(struct ccs_sensor *sensor) |
| 801 | 797 | { |
| 802 | 798 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); |
| 799 | + struct v4l2_fwnode_device_properties props; | |
| 803 | 800 | int rval; |
| 804 | 801 | |
| 805 | − rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 17); | |
| 802 | + rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 19); | |
| 806 | 803 | if (rval) |
| 807 | 804 | return rval; |
| 808 | 805 | |
| 809 | 806 | sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; |
| 810 | 807 | |
| 808 | + rval = v4l2_fwnode_device_parse(&client->dev, &props); | |
| 809 | + if (rval) | |
| 810 | + return rval; | |
| 811 | + | |
| 812 | + rval = v4l2_ctrl_new_fwnode_properties(&sensor->pixel_array->ctrl_handler, | |
| 813 | + &ccs_ctrl_ops, &props); | |
| 814 | + if (rval) | |
| 815 | + return rval; | |
| 816 | + | |
| 811 | 817 | switch (CCS_LIM(sensor, ANALOG_GAIN_CAPABILITY)) { |
| 812 | 818 | case CCS_ANALOG_GAIN_CAPABILITY_GLOBAL: { |
| 813 | 819 | struct { |
| @@ -2828,6 +2834,10 @@ static int ccs_identify_module(struct ccs_sensor *sensor) · 2014 unmodified lines | ||
| 2828 | 2834 | rval = ccs_read_addr_8only(sensor, |
| 2829 | 2835 | CCS_R_SENSOR_REVISION_NUMBER, |
| 2830 | 2836 | &minfo->sensor_revision_number); |
| 2837 | + if (!rval && !minfo->sensor_revision_number) | |
| 2838 | + rval = ccs_read_addr_8only(sensor, | |
| 2839 | + CCS_R_SENSOR_REVISION_NUMBER_16, | |
| 2840 | + &minfo->sensor_revision_number); | |
| 2831 | 2841 | if (!rval) |
| 2832 | 2842 | rval = ccs_read_addr_8only(sensor, |
| 2833 | 2843 | CCS_R_SENSOR_FIRMWARE_VERSION, |
| @@ -2870,7 +2880,7 @@ static int ccs_identify_module(struct ccs_sensor *sensor) · 36 unmodified lines | ||
| 2870 | 2880 | minfo->sensor_model_id); |
| 2871 | 2881 | |
| 2872 | 2882 | dev_dbg(&client->dev, |
| 2873 | − "sensor revision 0x%2.2x firmware version 0x%2.2x\n", | |
| 2883 | + "sensor revision 0x%4.4x firmware version 0x%2.2x\n", | |
| 2874 | 2884 | minfo->sensor_revision_number, minfo->sensor_firmware_version); |
| 2875 | 2885 | |
| 2876 | 2886 | if (minfo->ccs_version) { |
| @@ -2884,19 +2894,18 @@ static int ccs_identify_module(struct ccs_sensor *sensor) · 7 unmodified lines | ||
| 2884 | 2894 | "smia version %2.2d smiapp version %2.2d\n", |
| 2885 | 2895 | minfo->smia_version, minfo->smiapp_version); |
| 2886 | 2896 | minfo->name = SMIAPP_NAME; |
| 2887 | − } | |
| 2888 | − | |
| 2889 | − /* | |
| 2890 | − * Some modules have bad data in the lvalues below. Hope the | |
| 2891 | − * rvalues have better stuff. The lvalues are module | |
| 2892 | − * parameters whereas the rvalues are sensor parameters. | |
| 2893 | − */ | |
| 2894 | − if (minfo->sensor_smia_manufacturer_id && | |
| 2895 | − !minfo->smia_manufacturer_id && !minfo->model_id) { | |
| 2896 | − minfo->smia_manufacturer_id = | |
| 2897 | − minfo->sensor_smia_manufacturer_id; | |
| 2898 | − minfo->model_id = minfo->sensor_model_id; | |
| 2899 | − minfo->revision_number = minfo->sensor_revision_number; | |
| 2897 | + /* | |
| 2898 | + * Some modules have bad data in the lvalues below. Hope the | |
| 2899 | + * rvalues have better stuff. The lvalues are module | |
| 2900 | + * parameters whereas the rvalues are sensor parameters. | |
| 2901 | + */ | |
| 2902 | + if (minfo->sensor_smia_manufacturer_id && | |
| 2903 | + !minfo->smia_manufacturer_id && !minfo->model_id) { | |
| 2904 | + minfo->smia_manufacturer_id = | |
| 2905 | + minfo->sensor_smia_manufacturer_id; | |
| 2906 | + minfo->model_id = minfo->sensor_model_id; | |
| 2907 | + minfo->revision_number = minfo->sensor_revision_number; | |
| 2908 | + } | |
| 2900 | 2909 | } |
| 2901 | 2910 | |
| 2902 | 2911 | for (i = 0; i < ARRAY_SIZE(ccs_module_idents); i++) { |
| @@ -3185,7 +3194,6 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) · 282 unmodified lines | ||
| 3185 | 3194 | struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_UNKNOWN }; |
| 3186 | 3195 | struct fwnode_handle *ep; |
| 3187 | 3196 | struct fwnode_handle *fwnode = dev_fwnode(dev); |
| 3188 | − u32 rotation; | |
| 3189 | 3197 | unsigned int i; |
| 3190 | 3198 | int rval; |
| 3191 | 3199 | |
| @@ -3224,22 +3232,6 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) · 32 unmodified lines | ||
| 3224 | 3232 | goto out_err; |
| 3225 | 3233 | } |
| 3226 | 3234 | |
| 3227 | − rval = fwnode_property_read_u32(fwnode, "rotation", &rotation); | |
| 3228 | − if (!rval) { | |
| 3229 | − switch (rotation) { | |
| 3230 | − case 180: | |
| 3231 | − hwcfg->module_board_orient = | |
| 3232 | − CCS_MODULE_BOARD_ORIENT_180; | |
| 3233 | − fallthrough; | |
| 3234 | − case 0: | |
| 3235 | − break; | |
| 3236 | − default: | |
| 3237 | − dev_err(dev, "invalid rotation %u\n", rotation); | |
| 3238 | − rval = -EINVAL; | |
| 3239 | − goto out_err; | |
| 3240 | − } | |
| 3241 | − } | |
| 3242 | − | |
| 3243 | 3235 | rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", |
| 3244 | 3236 | &hwcfg->ext_clk); |
| 3245 | 3237 | if (rval) |
| @@ -3279,8 +3271,47 @@ out_err: · 33 unmodified lines | ||
| 3279 | 3271 | return rval; |
| 3280 | 3272 | } |
| 3281 | 3273 | |
| 3274 | +static int ccs_firmware_name(struct i2c_client *client, | |
| 3275 | + struct ccs_sensor *sensor, char *filename, | |
| 3276 | + size_t filename_size, bool is_module) | |
| 3277 | +{ | |
| 3278 | + const struct ccs_device *ccsdev = device_get_match_data(&client->dev); | |
| 3279 | + bool is_ccs = !(ccsdev->flags & CCS_DEVICE_FLAG_IS_SMIA); | |
| 3280 | + bool is_smiapp = sensor->minfo.smiapp_version; | |
| 3281 | + u16 manufacturer_id; | |
| 3282 | + u16 model_id; | |
| 3283 | + u16 revision_number; | |
| 3284 | + | |
| 3285 | + /* | |
| 3286 | + * Old SMIA is module-agnostic. Its sensor identification is based on | |
| 3287 | + * what now are those of the module. | |
| 3288 | + */ | |
| 3289 | + if (is_module || (!is_ccs && !is_smiapp)) { | |
| 3290 | + manufacturer_id = is_ccs ? | |
| 3291 | + sensor->minfo.mipi_manufacturer_id : | |
| 3292 | + sensor->minfo.smia_manufacturer_id; | |
| 3293 | + model_id = sensor->minfo.model_id; | |
| 3294 | + revision_number = sensor->minfo.revision_number; | |
| 3295 | + } else { | |
| 3296 | + manufacturer_id = is_ccs ? | |
| 3297 | + sensor->minfo.sensor_mipi_manufacturer_id : | |
| 3298 | + sensor->minfo.sensor_smia_manufacturer_id; | |
| 3299 | + model_id = sensor->minfo.sensor_model_id; | |
| 3300 | + revision_number = sensor->minfo.sensor_revision_number; | |
| 3301 | + } | |
| 3302 | + | |
| 3303 | + return snprintf(filename, filename_size, | |
| 3304 | + "ccs/%s-%s-%0*x-%4.4x-%0*x.fw", | |
| 3305 | + is_ccs ? "ccs" : is_smiapp ? "smiapp" : "smia", | |
| 3306 | + is_module || (!is_ccs && !is_smiapp) ? | |
| 3307 | + "module" : "sensor", | |
| 3308 | + is_ccs ? 4 : 2, manufacturer_id, model_id, | |
| 3309 | + !is_ccs && !is_module ? 2 : 4, revision_number); | |
| 3310 | +} | |
| 3311 | + | |
| 3282 | 3312 | static int ccs_probe(struct i2c_client *client) |
| 3283 | 3313 | { |
| 3314 | + const struct ccs_device *ccsdev = device_get_match_data(&client->dev); | |
| 3284 | 3315 | struct ccs_sensor *sensor; |
| 3285 | 3316 | const struct firmware *fw; |
| 3286 | 3317 | char filename[40]; |
| @@ -3389,11 +3420,8 @@ static int ccs_probe(struct i2c_client *client) · 102 unmodified lines | ||
| 3389 | 3420 | goto out_power_off; |
| 3390 | 3421 | } |
| 3391 | 3422 | |
| 3392 | − rval = snprintf(filename, sizeof(filename), | |
| 3393 | − "ccs/ccs-sensor-%4.4x-%4.4x-%4.4x.fw", | |
| 3394 | − sensor->minfo.sensor_mipi_manufacturer_id, | |
| 3395 | − sensor->minfo.sensor_model_id, | |
| 3396 | − sensor->minfo.sensor_revision_number); | |
| 3423 | + rval = ccs_firmware_name(client, sensor, filename, sizeof(filename), | |
| 3424 | + false); | |
| 3397 | 3425 | if (rval >= sizeof(filename)) { |
| 3398 | 3426 | rval = -ENOMEM; |
| 3399 | 3427 | goto out_power_off; |
| @@ -3406,21 +3434,21 @@ static int ccs_probe(struct i2c_client *client) · 6 unmodified lines | ||
| 3406 | 3434 | release_firmware(fw); |
| 3407 | 3435 | } |
| 3408 | 3436 | |
| 3409 | − rval = snprintf(filename, sizeof(filename), | |
| 3410 | − "ccs/ccs-module-%4.4x-%4.4x-%4.4x.fw", | |
| 3411 | − sensor->minfo.mipi_manufacturer_id, | |
| 3412 | − sensor->minfo.model_id, | |
| 3413 | − sensor->minfo.revision_number); | |
| 3414 | − if (rval >= sizeof(filename)) { | |
| 3415 | − rval = -ENOMEM; | |
| 3416 | − goto out_release_sdata; | |
| 3417 | − } | |
| 3437 | + if (!(ccsdev->flags & CCS_DEVICE_FLAG_IS_SMIA) || | |
| 3438 | + sensor->minfo.smiapp_version) { | |
| 3439 | + rval = ccs_firmware_name(client, sensor, filename, | |
| 3440 | + sizeof(filename), true); | |
| 3441 | + if (rval >= sizeof(filename)) { | |
| 3442 | + rval = -ENOMEM; | |
| 3443 | + goto out_release_sdata; | |
| 3444 | + } | |
| 3418 | 3445 | |
| 3419 | − rval = request_firmware(&fw, filename, &client->dev); | |
| 3420 | − if (!rval) { | |
| 3421 | − ccs_data_parse(&sensor->mdata, fw->data, fw->size, &client->dev, | |
| 3422 | − true); | |
| 3423 | − release_firmware(fw); | |
| 3446 | + rval = request_firmware(&fw, filename, &client->dev); | |
| 3447 | + if (!rval) { | |
| 3448 | + ccs_data_parse(&sensor->mdata, fw->data, fw->size, | |
| 3449 | + &client->dev, true); | |
| 3450 | + release_firmware(fw); | |
| 3451 | + } | |
| 3424 | 3452 | } |
| 3425 | 3453 | |
| 3426 | 3454 | rval = ccs_read_all_limits(sensor); |
| @@ -3437,25 +3465,6 @@ static int ccs_probe(struct i2c_client *client) · 10 unmodified lines | ||
| 3437 | 3465 | if (rval < 0) |
| 3438 | 3466 | goto out_free_ccs_limits; |
| 3439 | 3467 | |
| 3440 | − /* | |
| 3441 | − * Handle Sensor Module orientation on the board. | |
| 3442 | − * | |
| 3443 | − * The application of H-FLIP and V-FLIP on the sensor is modified by | |
| 3444 | − * the sensor orientation on the board. | |
| 3445 | − * | |
| 3446 | − * For CCS_BOARD_SENSOR_ORIENT_180 the default behaviour is to set | |
| 3447 | − * both H-FLIP and V-FLIP for normal operation which also implies | |
| 3448 | − * that a set/unset operation for user space HFLIP and VFLIP v4l2 | |
| 3449 | − * controls will need to be internally inverted. | |
| 3450 | − * | |
| 3451 | − * Rotation also changes the bayer pattern. | |
| 3452 | − */ | |
| 3453 | − if (sensor->hwcfg.module_board_orient == | |
| 3454 | − CCS_MODULE_BOARD_ORIENT_180) | |
| 3455 | − sensor->hvflip_inv_mask = | |
| 3456 | − CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR | | |
| 3457 | − CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; | |
| 3458 | − | |
| 3459 | 3468 | rval = ccs_call_quirk(sensor, limits); |
| 3460 | 3469 | if (rval) { |
| 3461 | 3470 | dev_err(&client->dev, "limits quirks failed\n"); |
| @@ -57,17 +57,6 @@ · 56 unmodified lines | ||
| 57 | 57 | #define CCS_LIM_AT(sensor, limit, offset) \ |
| 58 | 58 | ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) |
| 59 | 59 | |
| 60 | −/* | |
| 61 | − * Sometimes due to board layout considerations the camera module can be | |
| 62 | − * mounted rotated. The typical rotation used is 180 degrees which can be | |
| 63 | − * corrected by giving a default H-FLIP and V-FLIP in the sensor readout. | |
| 64 | − * FIXME: rotation also changes the bayer pattern. | |
| 65 | − */ | |
| 66 | −enum ccs_module_board_orient { | |
| 67 | − CCS_MODULE_BOARD_ORIENT_0 = 0, | |
| 68 | − CCS_MODULE_BOARD_ORIENT_180, | |
| 69 | −}; | |
| 70 | − | |
| 71 | 60 | struct ccs_flash_strobe_parms { |
| 72 | 61 | u8 mode; |
| 73 | 62 | u32 strobe_width_high_us; |
| @@ -90,8 +79,6 @@ struct ccs_hwconfig { · 16 unmodified lines | ||
| 90 | 79 | u32 csi_signalling_mode; /* CCS_CSI_SIGNALLING_MODE_* */ |
| 91 | 80 | u64 *op_sys_clock; |
| 92 | 81 | |
| 93 | − enum ccs_module_board_orient module_board_orient; | |
| 94 | − | |
| 95 | 82 | struct ccs_flash_strobe_parms *strobe_setup; |
| 96 | 83 | }; |
| 97 | 84 | |
| @@ -243,7 +230,6 @@ struct ccs_sensor { · 145 unmodified lines | ||
| 243 | 230 | u8 scale_m; |
| 244 | 231 | u8 scaling_mode; |
| 245 | 232 | |
| 246 | − u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ | |
| 247 | 233 | u8 frame_skip; |
| 248 | 234 | u16 embedded_start; /* embedded data start line */ |
| 249 | 235 | u16 embedded_end; |
| @@ -63,6 +63,14 @@ · 62 unmodified lines | ||
| 63 | 63 | #define HI556_REG_ISP_TPG_EN 0x01 |
| 64 | 64 | #define HI556_REG_TEST_PATTERN 0x0201 |
| 65 | 65 | |
| 66 | +/* HI556 native and active pixel array size. */ | |
| 67 | +#define HI556_NATIVE_WIDTH 2592U | |
| 68 | +#define HI556_NATIVE_HEIGHT 1944U | |
| 69 | +#define HI556_PIXEL_ARRAY_LEFT 0U | |
| 70 | +#define HI556_PIXEL_ARRAY_TOP 0U | |
| 71 | +#define HI556_PIXEL_ARRAY_WIDTH 2592U | |
| 72 | +#define HI556_PIXEL_ARRAY_HEIGHT 1944U | |
| 73 | + | |
| 66 | 74 | enum { |
| 67 | 75 | HI556_LINK_FREQ_437MHZ_INDEX, |
| 68 | 76 | }; |
| @@ -88,6 +96,9 @@ struct hi556_mode { · 19 unmodified lines | ||
| 88 | 96 | /* Frame height in pixels */ |
| 89 | 97 | u32 height; |
| 90 | 98 | |
| 99 | + /* Analog crop rectangle. */ | |
| 100 | + struct v4l2_rect crop; | |
| 101 | + | |
| 91 | 102 | /* Horizontal timining size */ |
| 92 | 103 | u32 llp; |
| 93 | 104 | |
| @@ -378,6 +389,49 @@ static const struct hi556_reg mode_2592x1944_regs[] = { · 284 unmodified lines | ||
| 378 | 389 | {0x0958, 0xbb80}, |
| 379 | 390 | }; |
| 380 | 391 | |
| 392 | +static const struct hi556_reg mode_2592x1444_regs[] = { | |
| 393 | + {0x0a00, 0x0000}, | |
| 394 | + {0x0b0a, 0x8252}, | |
| 395 | + {0x0f30, 0xe545}, | |
| 396 | + {0x0f32, 0x7067}, | |
| 397 | + {0x004a, 0x0100}, | |
| 398 | + {0x004c, 0x0000}, | |
| 399 | + {0x000c, 0x0022}, | |
| 400 | + {0x0008, 0x0b00}, | |
| 401 | + {0x005a, 0x0202}, | |
| 402 | + {0x0012, 0x000e}, | |
| 403 | + {0x0018, 0x0a33}, | |
| 404 | + {0x0022, 0x0008}, | |
| 405 | + {0x0028, 0x0017}, | |
| 406 | + {0x0024, 0x0122}, | |
| 407 | + {0x002a, 0x0127}, | |
| 408 | + {0x0026, 0x012a}, | |
| 409 | + {0x002c, 0x06cf}, | |
| 410 | + {0x002e, 0x1111}, | |
| 411 | + {0x0030, 0x1111}, | |
| 412 | + {0x0032, 0x1111}, | |
| 413 | + {0x0006, 0x0821}, | |
| 414 | + {0x0a22, 0x0000}, | |
| 415 | + {0x0a12, 0x0a20}, | |
| 416 | + {0x0a14, 0x05a4}, | |
| 417 | + {0x003e, 0x0000}, | |
| 418 | + {0x0074, 0x081f}, | |
| 419 | + {0x0070, 0x040f}, | |
| 420 | + {0x0804, 0x0300}, | |
| 421 | + {0x0806, 0x0100}, | |
| 422 | + {0x0a04, 0x014a}, | |
| 423 | + {0x090c, 0x0fdc}, | |
| 424 | + {0x090e, 0x002d}, | |
| 425 | + {0x0902, 0x4319}, | |
| 426 | + {0x0914, 0xc10a}, | |
| 427 | + {0x0916, 0x071f}, | |
| 428 | + {0x0918, 0x0408}, | |
| 429 | + {0x091a, 0x0c0d}, | |
| 430 | + {0x091c, 0x0f09}, | |
| 431 | + {0x091e, 0x0a00}, | |
| 432 | + {0x0958, 0xbb80}, | |
| 433 | +}; | |
| 434 | + | |
| 381 | 435 | static const struct hi556_reg mode_1296x972_regs[] = { |
| 382 | 436 | {0x0a00, 0x0000}, |
| 383 | 437 | {0x0b0a, 0x8259}, |
| @@ -450,8 +504,14 @@ static const struct hi556_link_freq_config link_freq_configs[] = { · 66 unmodified lines | ||
| 450 | 504 | |
| 451 | 505 | static const struct hi556_mode supported_modes[] = { |
| 452 | 506 | { |
| 453 | − .width = 2592, | |
| 454 | − .height = 1944, | |
| 507 | + .width = HI556_PIXEL_ARRAY_WIDTH, | |
| 508 | + .height = HI556_PIXEL_ARRAY_HEIGHT, | |
| 509 | + .crop = { | |
| 510 | + .left = HI556_PIXEL_ARRAY_LEFT, | |
| 511 | + .top = HI556_PIXEL_ARRAY_TOP, | |
| 512 | + .width = HI556_PIXEL_ARRAY_WIDTH, | |
| 513 | + .height = HI556_PIXEL_ARRAY_HEIGHT | |
| 514 | + }, | |
| 455 | 515 | .fll_def = HI556_FLL_30FPS, |
| 456 | 516 | .fll_min = HI556_FLL_30FPS_MIN, |
| 457 | 517 | .llp = 0x0b00, |
| @@ -461,9 +521,33 @@ static const struct hi556_mode supported_modes[] = { · 3 unmodified lines | ||
| 461 | 521 | }, |
| 462 | 522 | .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, |
| 463 | 523 | }, |
| 524 | + { | |
| 525 | + .width = HI556_PIXEL_ARRAY_WIDTH, | |
| 526 | + .height = 1444, | |
| 527 | + .crop = { | |
| 528 | + .left = HI556_PIXEL_ARRAY_LEFT, | |
| 529 | + .top = 250, | |
| 530 | + .width = HI556_PIXEL_ARRAY_WIDTH, | |
| 531 | + .height = 1444 | |
| 532 | + }, | |
| 533 | + .fll_def = 0x821, | |
| 534 | + .fll_min = 0x821, | |
| 535 | + .llp = 0x0b00, | |
| 536 | + .reg_list = { | |
| 537 | + .num_of_regs = ARRAY_SIZE(mode_2592x1444_regs), | |
| 538 | + .regs = mode_2592x1444_regs, | |
| 539 | + }, | |
| 540 | + .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, | |
| 541 | + }, | |
| 464 | 542 | { |
| 465 | 543 | .width = 1296, |
| 466 | 544 | .height = 972, |
| 545 | + .crop = { | |
| 546 | + .left = HI556_PIXEL_ARRAY_LEFT, | |
| 547 | + .top = HI556_PIXEL_ARRAY_TOP, | |
| 548 | + .width = HI556_PIXEL_ARRAY_WIDTH, | |
| 549 | + .height = HI556_PIXEL_ARRAY_HEIGHT | |
| 550 | + }, | |
| 467 | 551 | .fll_def = HI556_FLL_30FPS, |
| 468 | 552 | .fll_min = HI556_FLL_30FPS_MIN, |
| 469 | 553 | .llp = 0x0b00, |
| @@ -785,6 +869,58 @@ static int hi556_identify_module(struct hi556 *hi556) · 315 unmodified lines | ||
| 785 | 869 | return 0; |
| 786 | 870 | } |
| 787 | 871 | |
| 872 | +static const struct v4l2_rect * | |
| 873 | +__hi556_get_pad_crop(struct hi556 *hi556, | |
| 874 | + struct v4l2_subdev_state *sd_state, | |
| 875 | + unsigned int pad, enum v4l2_subdev_format_whence which) | |
| 876 | +{ | |
| 877 | + switch (which) { | |
| 878 | + case V4L2_SUBDEV_FORMAT_TRY: | |
| 879 | + return v4l2_subdev_get_try_crop(&hi556->sd, sd_state, pad); | |
| 880 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 881 | + return &hi556->cur_mode->crop; | |
| 882 | + } | |
| 883 | + | |
| 884 | + return NULL; | |
| 885 | +} | |
| 886 | + | |
| 887 | +static int hi556_get_selection(struct v4l2_subdev *sd, | |
| 888 | + struct v4l2_subdev_state *sd_state, | |
| 889 | + struct v4l2_subdev_selection *sel) | |
| 890 | +{ | |
| 891 | + switch (sel->target) { | |
| 892 | + case V4L2_SEL_TGT_CROP: { | |
| 893 | + struct hi556 *hi556 = to_hi556(sd); | |
| 894 | + | |
| 895 | + mutex_lock(&hi556->mutex); | |
| 896 | + sel->r = *__hi556_get_pad_crop(hi556, sd_state, sel->pad, | |
| 897 | + sel->which); | |
| 898 | + mutex_unlock(&hi556->mutex); | |
| 899 | + | |
| 900 | + return 0; | |
| 901 | + } | |
| 902 | + | |
| 903 | + case V4L2_SEL_TGT_NATIVE_SIZE: | |
| 904 | + sel->r.top = 0; | |
| 905 | + sel->r.left = 0; | |
| 906 | + sel->r.width = HI556_NATIVE_WIDTH; | |
| 907 | + sel->r.height = HI556_NATIVE_HEIGHT; | |
| 908 | + | |
| 909 | + return 0; | |
| 910 | + | |
| 911 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 912 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 913 | + sel->r.top = HI556_PIXEL_ARRAY_TOP; | |
| 914 | + sel->r.left = HI556_PIXEL_ARRAY_LEFT; | |
| 915 | + sel->r.width = HI556_PIXEL_ARRAY_WIDTH; | |
| 916 | + sel->r.height = HI556_PIXEL_ARRAY_HEIGHT; | |
| 917 | + | |
| 918 | + return 0; | |
| 919 | + } | |
| 920 | + | |
| 921 | + return -EINVAL; | |
| 922 | +} | |
| 923 | + | |
| 788 | 924 | static int hi556_start_streaming(struct hi556 *hi556) |
| 789 | 925 | { |
| 790 | 926 | struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); |
| @@ -1000,10 +1136,19 @@ static int hi556_enum_frame_size(struct v4l2_subdev *sd, · 209 unmodified lines | ||
| 1000 | 1136 | static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
| 1001 | 1137 | { |
| 1002 | 1138 | struct hi556 *hi556 = to_hi556(sd); |
| 1139 | + struct v4l2_rect *try_crop; | |
| 1003 | 1140 | |
| 1004 | 1141 | mutex_lock(&hi556->mutex); |
| 1005 | 1142 | hi556_assign_pad_format(&supported_modes[0], |
| 1006 | 1143 | v4l2_subdev_get_try_format(sd, fh->state, 0)); |
| 1144 | + | |
| 1145 | + /* Initialize try_crop rectangle. */ | |
| 1146 | + try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0); | |
| 1147 | + try_crop->top = HI556_PIXEL_ARRAY_TOP; | |
| 1148 | + try_crop->left = HI556_PIXEL_ARRAY_LEFT; | |
| 1149 | + try_crop->width = HI556_PIXEL_ARRAY_WIDTH; | |
| 1150 | + try_crop->height = HI556_PIXEL_ARRAY_HEIGHT; | |
| 1151 | + | |
| 1007 | 1152 | mutex_unlock(&hi556->mutex); |
| 1008 | 1153 | |
| 1009 | 1154 | return 0; |
| @@ -1016,6 +1161,7 @@ static const struct v4l2_subdev_video_ops hi556_video_ops = { · 6 unmodified lines | ||
| 1016 | 1161 | static const struct v4l2_subdev_pad_ops hi556_pad_ops = { |
| 1017 | 1162 | .set_fmt = hi556_set_format, |
| 1018 | 1163 | .get_fmt = hi556_get_format, |
| 1164 | + .get_selection = hi556_get_selection, | |
| 1019 | 1165 | .enum_mbus_code = hi556_enum_mbus_code, |
| 1020 | 1166 | .enum_frame_size = hi556_enum_frame_size, |
| 1021 | 1167 | }; |
| @@ -1472,21 +1472,26 @@ static int hi846_init_controls(struct hi846 *hi846) · 1471 unmodified lines | ||
| 1472 | 1472 | if (ctrl_hdlr->error) { |
| 1473 | 1473 | dev_err(&client->dev, "v4l ctrl handler error: %d\n", |
| 1474 | 1474 | ctrl_hdlr->error); |
| 1475 | − return ctrl_hdlr->error; | |
| 1475 | + ret = ctrl_hdlr->error; | |
| 1476 | + goto error; | |
| 1476 | 1477 | } |
| 1477 | 1478 | |
| 1478 | 1479 | ret = v4l2_fwnode_device_parse(&client->dev, &props); |
| 1479 | 1480 | if (ret) |
| 1480 | − return ret; | |
| 1481 | + goto error; | |
| 1481 | 1482 | |
| 1482 | 1483 | ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &hi846_ctrl_ops, |
| 1483 | 1484 | &props); |
| 1484 | 1485 | if (ret) |
| 1485 | − return ret; | |
| 1486 | + goto error; | |
| 1486 | 1487 | |
| 1487 | 1488 | hi846->sd.ctrl_handler = ctrl_hdlr; |
| 1488 | 1489 | |
| 1489 | 1490 | return 0; |
| 1491 | + | |
| 1492 | +error: | |
| 1493 | + v4l2_ctrl_handler_free(ctrl_hdlr); | |
| 1494 | + return ret; | |
| 1490 | 1495 | } |
| 1491 | 1496 | |
| 1492 | 1497 | static int hi846_set_video_mode(struct hi846 *hi846, int fps) |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/pm_runtime.h> |
| 10 | 10 | #include <media/v4l2-ctrls.h> |
| 11 | 11 | #include <media/v4l2-device.h> |
| 12 | +#include <media/v4l2-fwnode.h> | |
| 12 | 13 | #include <asm/unaligned.h> |
| 13 | 14 | |
| 14 | 15 | #define IMX258_REG_VALUE_08BIT 1 |
| @@ -1148,7 +1149,9 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = { · 1133 unmodified lines | ||
| 1148 | 1149 | static int imx258_init_controls(struct imx258 *imx258) |
| 1149 | 1150 | { |
| 1150 | 1151 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 1152 | + struct v4l2_fwnode_device_properties props; | |
| 1151 | 1153 | struct v4l2_ctrl_handler *ctrl_hdlr; |
| 1154 | + struct v4l2_ctrl *vflip, *hflip; | |
| 1152 | 1155 | s64 vblank_def; |
| 1153 | 1156 | s64 vblank_min; |
| 1154 | 1157 | s64 pixel_rate_min; |
| @@ -1156,7 +1159,7 @@ static int imx258_init_controls(struct imx258 *imx258) · 1 unmodified line | ||
| 1156 | 1159 | int ret; |
| 1157 | 1160 | |
| 1158 | 1161 | ctrl_hdlr = &imx258->ctrl_handler; |
| 1159 | − ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); | |
| 1162 | + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 13); | |
| 1160 | 1163 | if (ret) |
| 1161 | 1164 | return ret; |
| 1162 | 1165 | |
| @@ -1172,6 +1175,17 @@ static int imx258_init_controls(struct imx258 *imx258) · 9 unmodified lines | ||
| 1172 | 1175 | if (imx258->link_freq) |
| 1173 | 1176 | imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
| 1174 | 1177 | |
| 1178 | + /* The driver only supports one bayer order and flips by default. */ | |
| 1179 | + hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1180 | + V4L2_CID_HFLIP, 1, 1, 1, 1); | |
| 1181 | + if (hflip) | |
| 1182 | + hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1183 | + | |
| 1184 | + vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1185 | + V4L2_CID_VFLIP, 1, 1, 1, 1); | |
| 1186 | + if (vflip) | |
| 1187 | + vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1188 | + | |
| 1175 | 1189 | pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]); |
| 1176 | 1190 | pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]); |
| 1177 | 1191 | /* By default, PIXEL_RATE is read only */ |
| @@ -1232,6 +1246,15 @@ static int imx258_init_controls(struct imx258 *imx258) · 54 unmodified lines | ||
| 1232 | 1246 | goto error; |
| 1233 | 1247 | } |
| 1234 | 1248 | |
| 1249 | + ret = v4l2_fwnode_device_parse(&client->dev, &props); | |
| 1250 | + if (ret) | |
| 1251 | + goto error; | |
| 1252 | + | |
| 1253 | + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1254 | + &props); | |
| 1255 | + if (ret) | |
| 1256 | + goto error; | |
| 1257 | + | |
| 1235 | 1258 | imx258->sd.ctrl_handler = ctrl_hdlr; |
| 1236 | 1259 | |
| 1237 | 1260 | return 0; |
| @@ -1276,14 +1299,6 @@ static int imx258_probe(struct i2c_client *client) · 38 unmodified lines | ||
| 1276 | 1299 | return -EINVAL; |
| 1277 | 1300 | } |
| 1278 | 1301 | |
| 1279 | − /* | |
| 1280 | − * Check that the device is mounted upside down. The driver only | |
| 1281 | − * supports a single pixel order right now. | |
| 1282 | − */ | |
| 1283 | − ret = device_property_read_u32(&client->dev, "rotation", &val); | |
| 1284 | − if (ret || val != 180) | |
| 1285 | − return -EINVAL; | |
| 1286 | − | |
| 1287 | 1302 | /* Initialize subdev */ |
| 1288 | 1303 | v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); |
| 1289 | 1304 | |
| @@ -13,12 +13,17 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/gpio/consumer.h> |
| 14 | 14 | #include <linux/i2c.h> |
| 15 | 15 | #include <linux/module.h> |
| 16 | +#include <linux/of_device.h> | |
| 16 | 17 | #include <linux/pm_runtime.h> |
| 17 | 18 | #include <linux/regmap.h> |
| 18 | 19 | #include <linux/regulator/consumer.h> |
| 20 | + | |
| 21 | +#include <asm/unaligned.h> | |
| 22 | + | |
| 19 | 23 | #include <media/media-entity.h> |
| 20 | 24 | #include <media/v4l2-ctrls.h> |
| 21 | 25 | #include <media/v4l2-device.h> |
| 26 | +#include <media/v4l2-event.h> | |
| 22 | 27 | #include <media/v4l2-fwnode.h> |
| 23 | 28 | #include <media/v4l2-subdev.h> |
| 24 | 29 | |
| @@ -44,7 +49,9 @@ · 19 unmodified lines | ||
| 44 | 49 | #define IMX290_BLKLEVEL IMX290_REG_16BIT(0x300a) |
| 45 | 50 | #define IMX290_GAIN IMX290_REG_8BIT(0x3014) |
| 46 | 51 | #define IMX290_VMAX IMX290_REG_24BIT(0x3018) |
| 52 | +#define IMX290_VMAX_MAX 0x3ffff | |
| 47 | 53 | #define IMX290_HMAX IMX290_REG_16BIT(0x301c) |
| 54 | +#define IMX290_HMAX_MAX 0xffff | |
| 48 | 55 | #define IMX290_SHS1 IMX290_REG_24BIT(0x3020) |
| 49 | 56 | #define IMX290_WINWV_OB IMX290_REG_8BIT(0x303a) |
| 50 | 57 | #define IMX290_WINPV IMX290_REG_16BIT(0x303c) |
| @@ -98,13 +105,16 @@ · 47 unmodified lines | ||
| 98 | 105 | #define IMX290_TCLKPREPARE IMX290_REG_16BIT(0x3452) |
| 99 | 106 | #define IMX290_TLPX IMX290_REG_16BIT(0x3454) |
| 100 | 107 | #define IMX290_X_OUT_SIZE IMX290_REG_16BIT(0x3472) |
| 108 | +#define IMX290_INCKSEL7 IMX290_REG_8BIT(0x3480) | |
| 101 | 109 | |
| 102 | 110 | #define IMX290_PGCTRL_REGEN BIT(0) |
| 103 | 111 | #define IMX290_PGCTRL_THRU BIT(1) |
| 104 | 112 | #define IMX290_PGCTRL_MODE(n) ((n) << 4) |
| 105 | 113 | |
| 106 | −#define IMX290_VMAX_DEFAULT 1125 | |
| 114 | +/* Number of lines by which exposure must be less than VMAX */ | |
| 115 | +#define IMX290_EXPOSURE_OFFSET 2 | |
| 107 | 116 | |
| 117 | +#define IMX290_PIXEL_RATE 148500000 | |
| 108 | 118 | |
| 109 | 119 | /* |
| 110 | 120 | * The IMX290 pixel array is organized as follows: |
| @@ -157,26 +167,81 @@ · 46 unmodified lines | ||
| 157 | 167 | |
| 158 | 168 | #define IMX290_NUM_SUPPLIES 3 |
| 159 | 169 | |
| 170 | +enum imx290_colour_variant { | |
| 171 | + IMX290_VARIANT_COLOUR, | |
| 172 | + IMX290_VARIANT_MONO, | |
| 173 | + IMX290_VARIANT_MAX | |
| 174 | +}; | |
| 175 | + | |
| 176 | +enum imx290_model { | |
| 177 | + IMX290_MODEL_IMX290LQR, | |
| 178 | + IMX290_MODEL_IMX290LLR, | |
| 179 | + IMX290_MODEL_IMX327LQR, | |
| 180 | +}; | |
| 181 | + | |
| 182 | +struct imx290_model_info { | |
| 183 | + enum imx290_colour_variant colour_variant; | |
| 184 | + const struct imx290_regval *init_regs; | |
| 185 | + size_t init_regs_num; | |
| 186 | + const char *name; | |
| 187 | +}; | |
| 188 | + | |
| 189 | +enum imx290_clk_freq { | |
| 190 | + IMX290_CLK_37_125, | |
| 191 | + IMX290_CLK_74_25, | |
| 192 | + IMX290_NUM_CLK | |
| 193 | +}; | |
| 194 | + | |
| 160 | 195 | struct imx290_regval { |
| 161 | 196 | u32 reg; |
| 162 | 197 | u32 val; |
| 163 | 198 | }; |
| 164 | 199 | |
| 200 | +/* | |
| 201 | + * Clock configuration for registers INCKSEL1 to INCKSEL6. | |
| 202 | + */ | |
| 203 | +struct imx290_clk_cfg { | |
| 204 | + u8 incksel1; | |
| 205 | + u8 incksel2; | |
| 206 | + u8 incksel3; | |
| 207 | + u8 incksel4; | |
| 208 | + u8 incksel5; | |
| 209 | + u8 incksel6; | |
| 210 | +}; | |
| 211 | + | |
| 165 | 212 | struct imx290_mode { |
| 166 | 213 | u32 width; |
| 167 | 214 | u32 height; |
| 168 | − u32 hmax; | |
| 215 | + u32 hmax_min; | |
| 216 | + u32 vmax_min; | |
| 169 | 217 | u8 link_freq_index; |
| 218 | + u8 ctrl_07; | |
| 170 | 219 | |
| 171 | 220 | const struct imx290_regval *data; |
| 172 | 221 | u32 data_size; |
| 222 | + | |
| 223 | + const struct imx290_clk_cfg *clk_cfg; | |
| 224 | +}; | |
| 225 | + | |
| 226 | +struct imx290_csi_cfg { | |
| 227 | + u16 repetition; | |
| 228 | + u16 tclkpost; | |
| 229 | + u16 thszero; | |
| 230 | + u16 thsprepare; | |
| 231 | + u16 tclktrail; | |
| 232 | + u16 thstrail; | |
| 233 | + u16 tclkzero; | |
| 234 | + u16 tclkprepare; | |
| 235 | + u16 tlpx; | |
| 173 | 236 | }; |
| 174 | 237 | |
| 175 | 238 | struct imx290 { |
| 176 | 239 | struct device *dev; |
| 177 | 240 | struct clk *xclk; |
| 178 | 241 | struct regmap *regmap; |
| 242 | + enum imx290_clk_freq xclk_idx; | |
| 179 | 243 | u8 nlanes; |
| 244 | + const struct imx290_model_info *model; | |
| 180 | 245 | |
| 181 | 246 | struct v4l2_subdev sd; |
| 182 | 247 | struct media_pad pad; |
| @@ -188,9 +253,13 @@ struct imx290 { · 5 unmodified lines | ||
| 188 | 253 | |
| 189 | 254 | struct v4l2_ctrl_handler ctrls; |
| 190 | 255 | struct v4l2_ctrl *link_freq; |
| 191 | − struct v4l2_ctrl *pixel_rate; | |
| 192 | 256 | struct v4l2_ctrl *hblank; |
| 193 | 257 | struct v4l2_ctrl *vblank; |
| 258 | + struct v4l2_ctrl *exposure; | |
| 259 | + struct { | |
| 260 | + struct v4l2_ctrl *hflip; | |
| 261 | + struct v4l2_ctrl *vflip; | |
| 262 | + }; | |
| 194 | 263 | }; |
| 195 | 264 | |
| 196 | 265 | static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) |
| @@ -203,9 +272,6 @@ static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) · 6 unmodified lines | ||
| 203 | 272 | */ |
| 204 | 273 | |
| 205 | 274 | static const struct imx290_regval imx290_global_init_settings[] = { |
| 206 | − { IMX290_CTRL_07, IMX290_WINMODE_1080P }, | |
| 207 | − { IMX290_VMAX, IMX290_VMAX_DEFAULT }, | |
| 208 | − { IMX290_EXTCK_FREQ, 0x2520 }, | |
| 209 | 275 | { IMX290_WINWV_OB, 12 }, |
| 210 | 276 | { IMX290_WINPH, 0 }, |
| 211 | 277 | { IMX290_WINPV, 0 }, |
| @@ -213,10 +279,14 @@ static const struct imx290_regval imx290_global_init_settings[] = { · 1 unmodified line | ||
| 213 | 279 | { IMX290_WINWV, 1097 }, |
| 214 | 280 | { IMX290_XSOUTSEL, IMX290_XSOUTSEL_XVSOUTSEL_VSYNC | |
| 215 | 281 | IMX290_XSOUTSEL_XHSOUTSEL_HSYNC }, |
| 216 | − { IMX290_REG_8BIT(0x300f), 0x00 }, | |
| 217 | − { IMX290_REG_8BIT(0x3010), 0x21 }, | |
| 282 | + { IMX290_REG_8BIT(0x3011), 0x02 }, | |
| 218 | 283 | { IMX290_REG_8BIT(0x3012), 0x64 }, |
| 219 | 284 | { IMX290_REG_8BIT(0x3013), 0x00 }, |
| 285 | +}; | |
| 286 | + | |
| 287 | +static const struct imx290_regval imx290_global_init_settings_290[] = { | |
| 288 | + { IMX290_REG_8BIT(0x300f), 0x00 }, | |
| 289 | + { IMX290_REG_8BIT(0x3010), 0x21 }, | |
| 220 | 290 | { IMX290_REG_8BIT(0x3016), 0x09 }, |
| 221 | 291 | { IMX290_REG_8BIT(0x3070), 0x02 }, |
| 222 | 292 | { IMX290_REG_8BIT(0x3071), 0x11 }, |
| @@ -255,57 +325,40 @@ static const struct imx290_regval imx290_global_init_settings[] = { · 32 unmodified lines | ||
| 255 | 325 | { IMX290_REG_8BIT(0x33b0), 0x50 }, |
| 256 | 326 | { IMX290_REG_8BIT(0x33b2), 0x1a }, |
| 257 | 327 | { IMX290_REG_8BIT(0x33b3), 0x04 }, |
| 258 | − { IMX290_REG_8BIT(0x3480), 0x49 }, | |
| 328 | +}; | |
| 329 | + | |
| 330 | +#define IMX290_NUM_CLK_REGS 2 | |
| 331 | +static const struct imx290_regval xclk_regs[][IMX290_NUM_CLK_REGS] = { | |
| 332 | + [IMX290_CLK_37_125] = { | |
| 333 | + { IMX290_EXTCK_FREQ, (37125 * 256) / 1000 }, | |
| 334 | + { IMX290_INCKSEL7, 0x49 }, | |
| 335 | + }, | |
| 336 | + [IMX290_CLK_74_25] = { | |
| 337 | + { IMX290_EXTCK_FREQ, (74250 * 256) / 1000 }, | |
| 338 | + { IMX290_INCKSEL7, 0x92 }, | |
| 339 | + }, | |
| 340 | +}; | |
| 341 | + | |
| 342 | +static const struct imx290_regval imx290_global_init_settings_327[] = { | |
| 343 | + { IMX290_REG_8BIT(0x309e), 0x4A }, | |
| 344 | + { IMX290_REG_8BIT(0x309f), 0x4A }, | |
| 345 | + { IMX290_REG_8BIT(0x313b), 0x61 }, | |
| 259 | 346 | }; |
| 260 | 347 | |
| 261 | 348 | static const struct imx290_regval imx290_1080p_settings[] = { |
| 262 | 349 | /* mode settings */ |
| 263 | − { IMX290_CTRL_07, IMX290_WINMODE_1080P }, | |
| 264 | 350 | { IMX290_WINWV_OB, 12 }, |
| 265 | 351 | { IMX290_OPB_SIZE_V, 10 }, |
| 266 | 352 | { IMX290_X_OUT_SIZE, 1920 }, |
| 267 | 353 | { IMX290_Y_OUT_SIZE, 1080 }, |
| 268 | − { IMX290_INCKSEL1, 0x18 }, | |
| 269 | − { IMX290_INCKSEL2, 0x03 }, | |
| 270 | − { IMX290_INCKSEL3, 0x20 }, | |
| 271 | − { IMX290_INCKSEL4, 0x01 }, | |
| 272 | − { IMX290_INCKSEL5, 0x1a }, | |
| 273 | − { IMX290_INCKSEL6, 0x1a }, | |
| 274 | − /* data rate settings */ | |
| 275 | − { IMX290_REPETITION, 0x10 }, | |
| 276 | − { IMX290_TCLKPOST, 87 }, | |
| 277 | − { IMX290_THSZERO, 55 }, | |
| 278 | − { IMX290_THSPREPARE, 31 }, | |
| 279 | − { IMX290_TCLKTRAIL, 31 }, | |
| 280 | − { IMX290_THSTRAIL, 31 }, | |
| 281 | − { IMX290_TCLKZERO, 119 }, | |
| 282 | − { IMX290_TCLKPREPARE, 31 }, | |
| 283 | − { IMX290_TLPX, 23 }, | |
| 284 | 354 | }; |
| 285 | 355 | |
| 286 | 356 | static const struct imx290_regval imx290_720p_settings[] = { |
| 287 | 357 | /* mode settings */ |
| 288 | − { IMX290_CTRL_07, IMX290_WINMODE_720P }, | |
| 289 | 358 | { IMX290_WINWV_OB, 6 }, |
| 290 | 359 | { IMX290_OPB_SIZE_V, 4 }, |
| 291 | 360 | { IMX290_X_OUT_SIZE, 1280 }, |
| 292 | 361 | { IMX290_Y_OUT_SIZE, 720 }, |
| 293 | − { IMX290_INCKSEL1, 0x20 }, | |
| 294 | − { IMX290_INCKSEL2, 0x00 }, | |
| 295 | − { IMX290_INCKSEL3, 0x20 }, | |
| 296 | − { IMX290_INCKSEL4, 0x01 }, | |
| 297 | − { IMX290_INCKSEL5, 0x1a }, | |
| 298 | − { IMX290_INCKSEL6, 0x1a }, | |
| 299 | − /* data rate settings */ | |
| 300 | − { IMX290_REPETITION, 0x10 }, | |
| 301 | − { IMX290_TCLKPOST, 79 }, | |
| 302 | − { IMX290_THSZERO, 47 }, | |
| 303 | − { IMX290_THSPREPARE, 23 }, | |
| 304 | − { IMX290_TCLKTRAIL, 23 }, | |
| 305 | − { IMX290_THSTRAIL, 23 }, | |
| 306 | − { IMX290_TCLKZERO, 87 }, | |
| 307 | − { IMX290_TCLKPREPARE, 23 }, | |
| 308 | − { IMX290_TLPX, 23 }, | |
| 309 | 362 | }; |
| 310 | 363 | |
| 311 | 364 | static const struct imx290_regval imx290_10bit_settings[] = { |
| @@ -326,6 +379,58 @@ static const struct imx290_regval imx290_12bit_settings[] = { · 14 unmodified lines | ||
| 326 | 379 | { IMX290_CSI_DT_FMT, IMX290_CSI_DT_FMT_RAW12 }, |
| 327 | 380 | }; |
| 328 | 381 | |
| 382 | +static const struct imx290_csi_cfg imx290_csi_222_75mhz = { | |
| 383 | + /* 222.75MHz or 445.5Mbit/s per lane */ | |
| 384 | + .repetition = 0x10, | |
| 385 | + .tclkpost = 87, | |
| 386 | + .thszero = 55, | |
| 387 | + .thsprepare = 31, | |
| 388 | + .tclktrail = 31, | |
| 389 | + .thstrail = 31, | |
| 390 | + .tclkzero = 119, | |
| 391 | + .tclkprepare = 31, | |
| 392 | + .tlpx = 23, | |
| 393 | +}; | |
| 394 | + | |
| 395 | +static const struct imx290_csi_cfg imx290_csi_445_5mhz = { | |
| 396 | + /* 445.5MHz or 891Mbit/s per lane */ | |
| 397 | + .repetition = 0x00, | |
| 398 | + .tclkpost = 119, | |
| 399 | + .thszero = 103, | |
| 400 | + .thsprepare = 71, | |
| 401 | + .tclktrail = 55, | |
| 402 | + .thstrail = 63, | |
| 403 | + .tclkzero = 255, | |
| 404 | + .tclkprepare = 63, | |
| 405 | + .tlpx = 55, | |
| 406 | +}; | |
| 407 | + | |
| 408 | +static const struct imx290_csi_cfg imx290_csi_148_5mhz = { | |
| 409 | + /* 148.5MHz or 297Mbit/s per lane */ | |
| 410 | + .repetition = 0x10, | |
| 411 | + .tclkpost = 79, | |
| 412 | + .thszero = 47, | |
| 413 | + .thsprepare = 23, | |
| 414 | + .tclktrail = 23, | |
| 415 | + .thstrail = 23, | |
| 416 | + .tclkzero = 87, | |
| 417 | + .tclkprepare = 23, | |
| 418 | + .tlpx = 23, | |
| 419 | +}; | |
| 420 | + | |
| 421 | +static const struct imx290_csi_cfg imx290_csi_297mhz = { | |
| 422 | + /* 297MHz or 594Mbit/s per lane */ | |
| 423 | + .repetition = 0x00, | |
| 424 | + .tclkpost = 103, | |
| 425 | + .thszero = 87, | |
| 426 | + .thsprepare = 47, | |
| 427 | + .tclktrail = 39, | |
| 428 | + .thstrail = 47, | |
| 429 | + .tclkzero = 191, | |
| 430 | + .tclkprepare = 47, | |
| 431 | + .tlpx = 39, | |
| 432 | +}; | |
| 433 | + | |
| 329 | 434 | /* supported link frequencies */ |
| 330 | 435 | #define FREQ_INDEX_1080P 0 |
| 331 | 436 | #define FREQ_INDEX_720P 1 |
| @@ -333,6 +438,7 @@ static const s64 imx290_link_freq_2lanes[] = { · 1 unmodified line | ||
| 333 | 438 | [FREQ_INDEX_1080P] = 445500000, |
| 334 | 439 | [FREQ_INDEX_720P] = 297000000, |
| 335 | 440 | }; |
| 441 | + | |
| 336 | 442 | static const s64 imx290_link_freq_4lanes[] = { |
| 337 | 443 | [FREQ_INDEX_1080P] = 222750000, |
| 338 | 444 | [FREQ_INDEX_720P] = 148500000, |
| @@ -358,23 +464,71 @@ static inline int imx290_link_freqs_num(const struct imx290 *imx290) · 19 unmodified lines | ||
| 358 | 464 | return ARRAY_SIZE(imx290_link_freq_4lanes); |
| 359 | 465 | } |
| 360 | 466 | |
| 467 | +static const struct imx290_clk_cfg imx290_1080p_clock_config[] = { | |
| 468 | + [IMX290_CLK_37_125] = { | |
| 469 | + /* 37.125MHz clock config */ | |
| 470 | + .incksel1 = 0x18, | |
| 471 | + .incksel2 = 0x03, | |
| 472 | + .incksel3 = 0x20, | |
| 473 | + .incksel4 = 0x01, | |
| 474 | + .incksel5 = 0x1a, | |
| 475 | + .incksel6 = 0x1a, | |
| 476 | + }, | |
| 477 | + [IMX290_CLK_74_25] = { | |
| 478 | + /* 74.25MHz clock config */ | |
| 479 | + .incksel1 = 0x0c, | |
| 480 | + .incksel2 = 0x03, | |
| 481 | + .incksel3 = 0x10, | |
| 482 | + .incksel4 = 0x01, | |
| 483 | + .incksel5 = 0x1b, | |
| 484 | + .incksel6 = 0x1b, | |
| 485 | + }, | |
| 486 | +}; | |
| 487 | + | |
| 488 | +static const struct imx290_clk_cfg imx290_720p_clock_config[] = { | |
| 489 | + [IMX290_CLK_37_125] = { | |
| 490 | + /* 37.125MHz clock config */ | |
| 491 | + .incksel1 = 0x20, | |
| 492 | + .incksel2 = 0x00, | |
| 493 | + .incksel3 = 0x20, | |
| 494 | + .incksel4 = 0x01, | |
| 495 | + .incksel5 = 0x1a, | |
| 496 | + .incksel6 = 0x1a, | |
| 497 | + }, | |
| 498 | + [IMX290_CLK_74_25] = { | |
| 499 | + /* 74.25MHz clock config */ | |
| 500 | + .incksel1 = 0x10, | |
| 501 | + .incksel2 = 0x00, | |
| 502 | + .incksel3 = 0x10, | |
| 503 | + .incksel4 = 0x01, | |
| 504 | + .incksel5 = 0x1b, | |
| 505 | + .incksel6 = 0x1b, | |
| 506 | + }, | |
| 507 | +}; | |
| 508 | + | |
| 361 | 509 | /* Mode configs */ |
| 362 | 510 | static const struct imx290_mode imx290_modes_2lanes[] = { |
| 363 | 511 | { |
| 364 | 512 | .width = 1920, |
| 365 | 513 | .height = 1080, |
| 366 | − .hmax = 4400, | |
| 514 | + .hmax_min = 2200, | |
| 515 | + .vmax_min = 1125, | |
| 367 | 516 | .link_freq_index = FREQ_INDEX_1080P, |
| 517 | + .ctrl_07 = IMX290_WINMODE_1080P, | |
| 368 | 518 | .data = imx290_1080p_settings, |
| 369 | 519 | .data_size = ARRAY_SIZE(imx290_1080p_settings), |
| 520 | + .clk_cfg = imx290_1080p_clock_config, | |
| 370 | 521 | }, |
| 371 | 522 | { |
| 372 | 523 | .width = 1280, |
| 373 | 524 | .height = 720, |
| 374 | − .hmax = 6600, | |
| 525 | + .hmax_min = 3300, | |
| 526 | + .vmax_min = 750, | |
| 375 | 527 | .link_freq_index = FREQ_INDEX_720P, |
| 528 | + .ctrl_07 = IMX290_WINMODE_720P, | |
| 376 | 529 | .data = imx290_720p_settings, |
| 377 | 530 | .data_size = ARRAY_SIZE(imx290_720p_settings), |
| 531 | + .clk_cfg = imx290_720p_clock_config, | |
| 378 | 532 | }, |
| 379 | 533 | }; |
| 380 | 534 | |
| @@ -382,18 +536,24 @@ static const struct imx290_mode imx290_modes_4lanes[] = { · 1 unmodified line | ||
| 382 | 536 | { |
| 383 | 537 | .width = 1920, |
| 384 | 538 | .height = 1080, |
| 385 | − .hmax = 2200, | |
| 539 | + .hmax_min = 2200, | |
| 540 | + .vmax_min = 1125, | |
| 386 | 541 | .link_freq_index = FREQ_INDEX_1080P, |
| 542 | + .ctrl_07 = IMX290_WINMODE_1080P, | |
| 387 | 543 | .data = imx290_1080p_settings, |
| 388 | 544 | .data_size = ARRAY_SIZE(imx290_1080p_settings), |
| 545 | + .clk_cfg = imx290_1080p_clock_config, | |
| 389 | 546 | }, |
| 390 | 547 | { |
| 391 | 548 | .width = 1280, |
| 392 | 549 | .height = 720, |
| 393 | − .hmax = 3300, | |
| 550 | + .hmax_min = 3300, | |
| 551 | + .vmax_min = 750, | |
| 394 | 552 | .link_freq_index = FREQ_INDEX_720P, |
| 553 | + .ctrl_07 = IMX290_WINMODE_720P, | |
| 395 | 554 | .data = imx290_720p_settings, |
| 396 | 555 | .data_size = ARRAY_SIZE(imx290_720p_settings), |
| 556 | + .clk_cfg = imx290_720p_clock_config, | |
| 397 | 557 | }, |
| 398 | 558 | }; |
| 399 | 559 | |
| @@ -414,7 +574,7 @@ static inline int imx290_modes_num(const struct imx290 *imx290) · 14 unmodified lines | ||
| 414 | 574 | } |
| 415 | 575 | |
| 416 | 576 | struct imx290_format_info { |
| 417 | − u32 code; | |
| 577 | + u32 code[IMX290_VARIANT_MAX]; | |
| 418 | 578 | u8 bpp; |
| 419 | 579 | const struct imx290_regval *regs; |
| 420 | 580 | unsigned int num_regs; |
| @@ -422,26 +582,33 @@ struct imx290_format_info { · 1 unmodified line | ||
| 422 | 582 | |
| 423 | 583 | static const struct imx290_format_info imx290_formats[] = { |
| 424 | 584 | { |
| 425 | − .code = MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 585 | + .code = { | |
| 586 | + [IMX290_VARIANT_COLOUR] = MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 587 | + [IMX290_VARIANT_MONO] = MEDIA_BUS_FMT_Y10_1X10 | |
| 588 | + }, | |
| 426 | 589 | .bpp = 10, |
| 427 | 590 | .regs = imx290_10bit_settings, |
| 428 | 591 | .num_regs = ARRAY_SIZE(imx290_10bit_settings), |
| 429 | 592 | }, { |
| 430 | − .code = MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 593 | + .code = { | |
| 594 | + [IMX290_VARIANT_COLOUR] = MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 595 | + [IMX290_VARIANT_MONO] = MEDIA_BUS_FMT_Y12_1X12 | |
| 596 | + }, | |
| 431 | 597 | .bpp = 12, |
| 432 | 598 | .regs = imx290_12bit_settings, |
| 433 | 599 | .num_regs = ARRAY_SIZE(imx290_12bit_settings), |
| 434 | 600 | } |
| 435 | 601 | }; |
| 436 | 602 | |
| 437 | −static const struct imx290_format_info *imx290_format_info(u32 code) | |
| 603 | +static const struct imx290_format_info * | |
| 604 | +imx290_format_info(const struct imx290 *imx290, u32 code) | |
| 438 | 605 | { |
| 439 | 606 | unsigned int i; |
| 440 | 607 | |
| 441 | 608 | for (i = 0; i < ARRAY_SIZE(imx290_formats); ++i) { |
| 442 | 609 | const struct imx290_format_info *info = &imx290_formats[i]; |
| 443 | 610 | |
| 444 | − if (info->code == code) | |
| 611 | + if (info->code[imx290->model->colour_variant] == code) | |
| 445 | 612 | return info; |
| 446 | 613 | } |
| 447 | 614 | |
| @@ -461,28 +628,30 @@ static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *val · 13 unmodified lines | ||
| 461 | 628 | data, (addr >> IMX290_REG_SIZE_SHIFT) & 3); |
| 462 | 629 | if (ret < 0) { |
| 463 | 630 | dev_err(imx290->dev, "%u-bit read from 0x%04x failed: %d\n", |
| 464 | − ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8, | |
| 631 | + ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8, | |
| 465 | 632 | addr & IMX290_REG_ADDR_MASK, ret); |
| 466 | 633 | return ret; |
| 467 | 634 | } |
| 468 | 635 | |
| 469 | − *value = (data[2] << 16) | (data[1] << 8) | data[0]; | |
| 636 | + *value = get_unaligned_le24(data); | |
| 470 | 637 | return 0; |
| 471 | 638 | } |
| 472 | 639 | |
| 473 | 640 | static int imx290_write(struct imx290 *imx290, u32 addr, u32 value, int *err) |
| 474 | 641 | { |
| 475 | − u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 }; | |
| 642 | + u8 data[3]; | |
| 476 | 643 | int ret; |
| 477 | 644 | |
| 478 | 645 | if (err && *err) |
| 479 | 646 | return *err; |
| 480 | 647 | |
| 648 | + put_unaligned_le24(value, data); | |
| 649 | + | |
| 481 | 650 | ret = regmap_raw_write(imx290->regmap, addr & IMX290_REG_ADDR_MASK, |
| 482 | 651 | data, (addr >> IMX290_REG_SIZE_SHIFT) & 3); |
| 483 | 652 | if (ret < 0) { |
| 484 | 653 | dev_err(imx290->dev, "%u-bit write to 0x%04x failed: %d\n", |
| 485 | − ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8, | |
| 654 | + ((addr >> IMX290_REG_SIZE_SHIFT) & 3) * 8, | |
| 486 | 655 | addr & IMX290_REG_ADDR_MASK, ret); |
| 487 | 656 | if (err) |
| 488 | 657 | *err = ret; |
| @@ -510,24 +679,33 @@ static int imx290_set_register_array(struct imx290 *imx290, · 21 unmodified lines | ||
| 510 | 679 | return 0; |
| 511 | 680 | } |
| 512 | 681 | |
| 682 | +static int imx290_set_clock(struct imx290 *imx290) | |
| 683 | +{ | |
| 684 | + const struct imx290_mode *mode = imx290->current_mode; | |
| 685 | + enum imx290_clk_freq clk_idx = imx290->xclk_idx; | |
| 686 | + const struct imx290_clk_cfg *clk_cfg = &mode->clk_cfg[clk_idx]; | |
| 687 | + int ret; | |
| 688 | + | |
| 689 | + ret = imx290_set_register_array(imx290, xclk_regs[clk_idx], | |
| 690 | + IMX290_NUM_CLK_REGS); | |
| 691 | + | |
| 692 | + imx290_write(imx290, IMX290_INCKSEL1, clk_cfg->incksel1, &ret); | |
| 693 | + imx290_write(imx290, IMX290_INCKSEL2, clk_cfg->incksel2, &ret); | |
| 694 | + imx290_write(imx290, IMX290_INCKSEL3, clk_cfg->incksel3, &ret); | |
| 695 | + imx290_write(imx290, IMX290_INCKSEL4, clk_cfg->incksel4, &ret); | |
| 696 | + imx290_write(imx290, IMX290_INCKSEL5, clk_cfg->incksel5, &ret); | |
| 697 | + imx290_write(imx290, IMX290_INCKSEL6, clk_cfg->incksel6, &ret); | |
| 698 | + | |
| 699 | + return ret; | |
| 700 | +} | |
| 701 | + | |
| 513 | 702 | static int imx290_set_data_lanes(struct imx290 *imx290) |
| 514 | 703 | { |
| 515 | 704 | int ret = 0; |
| 516 | − u32 frsel; | |
| 517 | − | |
| 518 | − switch (imx290->nlanes) { | |
| 519 | − case 2: | |
| 520 | − default: | |
| 521 | − frsel = 0x02; | |
| 522 | − break; | |
| 523 | − case 4: | |
| 524 | − frsel = 0x01; | |
| 525 | − break; | |
| 526 | − } | |
| 527 | 705 | |
| 528 | 706 | imx290_write(imx290, IMX290_PHY_LANE_NUM, imx290->nlanes - 1, &ret); |
| 529 | 707 | imx290_write(imx290, IMX290_CSI_LANE_MODE, imx290->nlanes - 1, &ret); |
| 530 | − imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret); | |
| 708 | + imx290_write(imx290, IMX290_FR_FDG_SEL, 0x01, &ret); | |
| 531 | 709 | |
| 532 | 710 | return ret; |
| 533 | 711 | } |
| @@ -536,19 +714,55 @@ static int imx290_set_black_level(struct imx290 *imx290, · 2 unmodified lines | ||
| 536 | 714 | const struct v4l2_mbus_framefmt *format, |
| 537 | 715 | unsigned int black_level, int *err) |
| 538 | 716 | { |
| 539 | − unsigned int bpp = imx290_format_info(format->code)->bpp; | |
| 717 | + unsigned int bpp = imx290_format_info(imx290, format->code)->bpp; | |
| 540 | 718 | |
| 541 | 719 | return imx290_write(imx290, IMX290_BLKLEVEL, |
| 542 | 720 | black_level >> (16 - bpp), err); |
| 543 | 721 | } |
| 544 | 722 | |
| 723 | +static int imx290_set_csi_config(struct imx290 *imx290) | |
| 724 | +{ | |
| 725 | + const s64 *link_freqs = imx290_link_freqs_ptr(imx290); | |
| 726 | + const struct imx290_csi_cfg *csi_cfg; | |
| 727 | + int ret = 0; | |
| 728 | + | |
| 729 | + switch (link_freqs[imx290->current_mode->link_freq_index]) { | |
| 730 | + case 445500000: | |
| 731 | + csi_cfg = &imx290_csi_445_5mhz; | |
| 732 | + break; | |
| 733 | + case 297000000: | |
| 734 | + csi_cfg = &imx290_csi_297mhz; | |
| 735 | + break; | |
| 736 | + case 222750000: | |
| 737 | + csi_cfg = &imx290_csi_222_75mhz; | |
| 738 | + break; | |
| 739 | + case 148500000: | |
| 740 | + csi_cfg = &imx290_csi_148_5mhz; | |
| 741 | + break; | |
| 742 | + default: | |
| 743 | + return -EINVAL; | |
| 744 | + } | |
| 745 | + | |
| 746 | + imx290_write(imx290, IMX290_REPETITION, csi_cfg->repetition, &ret); | |
| 747 | + imx290_write(imx290, IMX290_TCLKPOST, csi_cfg->tclkpost, &ret); | |
| 748 | + imx290_write(imx290, IMX290_THSZERO, csi_cfg->thszero, &ret); | |
| 749 | + imx290_write(imx290, IMX290_THSPREPARE, csi_cfg->thsprepare, &ret); | |
| 750 | + imx290_write(imx290, IMX290_TCLKTRAIL, csi_cfg->tclktrail, &ret); | |
| 751 | + imx290_write(imx290, IMX290_THSTRAIL, csi_cfg->thstrail, &ret); | |
| 752 | + imx290_write(imx290, IMX290_TCLKZERO, csi_cfg->tclkzero, &ret); | |
| 753 | + imx290_write(imx290, IMX290_TCLKPREPARE, csi_cfg->tclkprepare, &ret); | |
| 754 | + imx290_write(imx290, IMX290_TLPX, csi_cfg->tlpx, &ret); | |
| 755 | + | |
| 756 | + return ret; | |
| 757 | +} | |
| 758 | + | |
| 545 | 759 | static int imx290_setup_format(struct imx290 *imx290, |
| 546 | 760 | const struct v4l2_mbus_framefmt *format) |
| 547 | 761 | { |
| 548 | 762 | const struct imx290_format_info *info; |
| 549 | 763 | int ret; |
| 550 | 764 | |
| 551 | − info = imx290_format_info(format->code); | |
| 765 | + info = imx290_format_info(imx290, format->code); | |
| 552 | 766 | |
| 553 | 767 | ret = imx290_set_register_array(imx290, info->regs, info->num_regs); |
| 554 | 768 | if (ret < 0) { |
| @@ -563,6 +777,16 @@ static int imx290_setup_format(struct imx290 *imx290, · 8 unmodified lines | ||
| 563 | 777 | /* ---------------------------------------------------------------------------- |
| 564 | 778 | * Controls |
| 565 | 779 | */ |
| 780 | +static void imx290_exposure_update(struct imx290 *imx290, | |
| 781 | + const struct imx290_mode *mode) | |
| 782 | +{ | |
| 783 | + unsigned int exposure_max; | |
| 784 | + | |
| 785 | + exposure_max = imx290->vblank->val + mode->height - | |
| 786 | + IMX290_EXPOSURE_OFFSET; | |
| 787 | + __v4l2_ctrl_modify_range(imx290->exposure, 1, exposure_max, 1, | |
| 788 | + exposure_max); | |
| 789 | +} | |
| 566 | 790 | |
| 567 | 791 | static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) |
| 568 | 792 | { |
| @@ -570,7 +794,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) · 1 unmodified line | ||
| 570 | 794 | struct imx290, ctrls); |
| 571 | 795 | const struct v4l2_mbus_framefmt *format; |
| 572 | 796 | struct v4l2_subdev_state *state; |
| 573 | − int ret = 0; | |
| 797 | + int ret = 0, vmax; | |
| 574 | 798 | |
| 575 | 799 | /* |
| 576 | 800 | * Return immediately for controls that don't need to be applied to the |
| @@ -579,6 +803,11 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) · 2 unmodified lines | ||
| 579 | 803 | if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) |
| 580 | 804 | return 0; |
| 581 | 805 | |
| 806 | + if (ctrl->id == V4L2_CID_VBLANK) { | |
| 807 | + /* Changing vblank changes the allowed range for exposure. */ | |
| 808 | + imx290_exposure_update(imx290, imx290->current_mode); | |
| 809 | + } | |
| 810 | + | |
| 582 | 811 | /* V4L2 controls values will be applied only when power is already up */ |
| 583 | 812 | if (!pm_runtime_get_if_in_use(imx290->dev)) |
| 584 | 813 | return 0; |
| @@ -591,9 +820,23 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) · 6 unmodified lines | ||
| 591 | 820 | ret = imx290_write(imx290, IMX290_GAIN, ctrl->val, NULL); |
| 592 | 821 | break; |
| 593 | 822 | |
| 823 | + case V4L2_CID_VBLANK: | |
| 824 | + ret = imx290_write(imx290, IMX290_VMAX, | |
| 825 | + ctrl->val + imx290->current_mode->height, | |
| 826 | + NULL); | |
| 827 | + /* | |
| 828 | + * Due to the way that exposure is programmed in this sensor in | |
| 829 | + * relation to VMAX, we have to reprogramme it whenever VMAX is | |
| 830 | + * changed. | |
| 831 | + * Update ctrl so that the V4L2_CID_EXPOSURE case can refer to | |
| 832 | + * it. | |
| 833 | + */ | |
| 834 | + ctrl = imx290->exposure; | |
| 835 | + fallthrough; | |
| 594 | 836 | case V4L2_CID_EXPOSURE: |
| 837 | + vmax = imx290->vblank->val + imx290->current_mode->height; | |
| 595 | 838 | ret = imx290_write(imx290, IMX290_SHS1, |
| 596 | − IMX290_VMAX_DEFAULT - ctrl->val - 1, NULL); | |
| 839 | + vmax - ctrl->val - 1, NULL); | |
| 597 | 840 | break; |
| 598 | 841 | |
| 599 | 842 | case V4L2_CID_TEST_PATTERN: |
| @@ -612,6 +855,26 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) · 12 unmodified lines | ||
| 612 | 855 | } |
| 613 | 856 | break; |
| 614 | 857 | |
| 858 | + case V4L2_CID_HBLANK: | |
| 859 | + ret = imx290_write(imx290, IMX290_HMAX, | |
| 860 | + ctrl->val + imx290->current_mode->width, | |
| 861 | + NULL); | |
| 862 | + break; | |
| 863 | + | |
| 864 | + case V4L2_CID_HFLIP: | |
| 865 | + case V4L2_CID_VFLIP: | |
| 866 | + { | |
| 867 | + u32 reg; | |
| 868 | + | |
| 869 | + reg = imx290->current_mode->ctrl_07; | |
| 870 | + if (imx290->hflip->val) | |
| 871 | + reg |= IMX290_HREVERSE; | |
| 872 | + if (imx290->vflip->val) | |
| 873 | + reg |= IMX290_VREVERSE; | |
| 874 | + ret = imx290_write(imx290, IMX290_CTRL_07, reg, NULL); | |
| 875 | + break; | |
| 876 | + } | |
| 877 | + | |
| 615 | 878 | default: |
| 616 | 879 | ret = -EINVAL; |
| 617 | 880 | break; |
| @@ -642,20 +905,17 @@ static void imx290_ctrl_update(struct imx290 *imx290, · 24 unmodified lines | ||
| 642 | 905 | const struct v4l2_mbus_framefmt *format, |
| 643 | 906 | const struct imx290_mode *mode) |
| 644 | 907 | { |
| 645 | − unsigned int hblank = mode->hmax - mode->width; | |
| 646 | − unsigned int vblank = IMX290_VMAX_DEFAULT - mode->height; | |
| 647 | − s64 link_freq = imx290_link_freqs_ptr(imx290)[mode->link_freq_index]; | |
| 648 | − u64 pixel_rate; | |
| 649 | − | |
| 650 | − /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ | |
| 651 | − pixel_rate = link_freq * 2 * imx290->nlanes; | |
| 652 | − do_div(pixel_rate, imx290_format_info(format->code)->bpp); | |
| 908 | + unsigned int hblank_min = mode->hmax_min - mode->width; | |
| 909 | + unsigned int hblank_max = IMX290_HMAX_MAX - mode->width; | |
| 910 | + unsigned int vblank_min = mode->vmax_min - mode->height; | |
| 911 | + unsigned int vblank_max = IMX290_VMAX_MAX - mode->height; | |
| 653 | 912 | |
| 654 | 913 | __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); |
| 655 | − __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, pixel_rate); | |
| 656 | 914 | |
| 657 | − __v4l2_ctrl_modify_range(imx290->hblank, hblank, hblank, 1, hblank); | |
| 658 | − __v4l2_ctrl_modify_range(imx290->vblank, vblank, vblank, 1, vblank); | |
| 915 | + __v4l2_ctrl_modify_range(imx290->hblank, hblank_min, hblank_max, 1, | |
| 916 | + hblank_min); | |
| 917 | + __v4l2_ctrl_modify_range(imx290->vblank, vblank_min, vblank_max, 1, | |
| 918 | + vblank_min); | |
| 659 | 919 | } |
| 660 | 920 | |
| 661 | 921 | static int imx290_ctrl_init(struct imx290 *imx290) |
| @@ -667,7 +927,7 @@ static int imx290_ctrl_init(struct imx290 *imx290) · 5 unmodified lines | ||
| 667 | 927 | if (ret < 0) |
| 668 | 928 | return ret; |
| 669 | 929 | |
| 670 | − v4l2_ctrl_handler_init(&imx290->ctrls, 9); | |
| 930 | + v4l2_ctrl_handler_init(&imx290->ctrls, 11); | |
| 671 | 931 | |
| 672 | 932 | /* |
| 673 | 933 | * The sensor has an analog gain and a digital gain, both controlled |
| @@ -685,9 +945,13 @@ static int imx290_ctrl_init(struct imx290 *imx290) · 11 unmodified lines | ||
| 685 | 945 | v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, |
| 686 | 946 | V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0); |
| 687 | 947 | |
| 688 | − v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, | |
| 689 | − V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1, | |
| 690 | − IMX290_VMAX_DEFAULT - 2); | |
| 948 | + /* | |
| 949 | + * Correct range will be determined through imx290_ctrl_update setting | |
| 950 | + * V4L2_CID_VBLANK. | |
| 951 | + */ | |
| 952 | + imx290->exposure = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, | |
| 953 | + V4L2_CID_EXPOSURE, 1, 65535, 1, | |
| 954 | + 65535); | |
| 691 | 955 | |
| 692 | 956 | /* |
| 693 | 957 | * Set the link frequency, pixel rate, horizontal blanking and vertical |
| @@ -702,24 +966,29 @@ static int imx290_ctrl_init(struct imx290 *imx290) · 8 unmodified lines | ||
| 702 | 966 | if (imx290->link_freq) |
| 703 | 967 | imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
| 704 | 968 | |
| 705 | − imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, | |
| 706 | − V4L2_CID_PIXEL_RATE, | |
| 707 | − 1, INT_MAX, 1, 1); | |
| 969 | + v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, V4L2_CID_PIXEL_RATE, | |
| 970 | + IMX290_PIXEL_RATE, IMX290_PIXEL_RATE, 1, | |
| 971 | + IMX290_PIXEL_RATE); | |
| 708 | 972 | |
| 709 | 973 | v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, |
| 710 | 974 | V4L2_CID_TEST_PATTERN, |
| 711 | 975 | ARRAY_SIZE(imx290_test_pattern_menu) - 1, |
| 712 | 976 | 0, 0, imx290_test_pattern_menu); |
| 713 | 977 | |
| 978 | + /* | |
| 979 | + * Actual range will be set from imx290_ctrl_update later in the probe. | |
| 980 | + */ | |
| 714 | 981 | imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, |
| 715 | 982 | V4L2_CID_HBLANK, 1, 1, 1, 1); |
| 716 | − if (imx290->hblank) | |
| 717 | − imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 718 | 983 | |
| 719 | 984 | imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, |
| 720 | 985 | V4L2_CID_VBLANK, 1, 1, 1, 1); |
| 721 | − if (imx290->vblank) | |
| 722 | − imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 986 | + | |
| 987 | + imx290->hflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, | |
| 988 | + V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 989 | + imx290->vflip = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, | |
| 990 | + V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 991 | + v4l2_ctrl_cluster(2, &imx290->hflip); | |
| 723 | 992 | |
| 724 | 993 | v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops, |
| 725 | 994 | &props); |
| @@ -748,17 +1017,37 @@ static int imx290_start_streaming(struct imx290 *imx290, · 22 unmodified lines | ||
| 748 | 1017 | |
| 749 | 1018 | /* Set init register settings */ |
| 750 | 1019 | ret = imx290_set_register_array(imx290, imx290_global_init_settings, |
| 751 | − ARRAY_SIZE( | |
| 752 | − imx290_global_init_settings)); | |
| 1020 | + ARRAY_SIZE(imx290_global_init_settings)); | |
| 753 | 1021 | if (ret < 0) { |
| 754 | 1022 | dev_err(imx290->dev, "Could not set init registers\n"); |
| 755 | 1023 | return ret; |
| 756 | 1024 | } |
| 757 | 1025 | |
| 1026 | + /* Set mdel specific init register settings */ | |
| 1027 | + ret = imx290_set_register_array(imx290, imx290->model->init_regs, | |
| 1028 | + imx290->model->init_regs_num); | |
| 1029 | + if (ret < 0) { | |
| 1030 | + dev_err(imx290->dev, "Could not set model specific init registers\n"); | |
| 1031 | + return ret; | |
| 1032 | + } | |
| 1033 | + | |
| 1034 | + /* Set clock parameters based on mode and xclk */ | |
| 1035 | + ret = imx290_set_clock(imx290); | |
| 1036 | + if (ret < 0) { | |
| 1037 | + dev_err(imx290->dev, "Could not set clocks - %d\n", ret); | |
| 1038 | + return ret; | |
| 1039 | + } | |
| 1040 | + | |
| 758 | 1041 | /* Set data lane count */ |
| 759 | 1042 | ret = imx290_set_data_lanes(imx290); |
| 760 | 1043 | if (ret < 0) { |
| 761 | − dev_err(imx290->dev, "Could not set data lanes\n"); | |
| 1044 | + dev_err(imx290->dev, "Could not set data lanes - %d\n", ret); | |
| 1045 | + return ret; | |
| 1046 | + } | |
| 1047 | + | |
| 1048 | + ret = imx290_set_csi_config(imx290); | |
| 1049 | + if (ret < 0) { | |
| 1050 | + dev_err(imx290->dev, "Could not set csi cfg - %d\n", ret); | |
| 762 | 1051 | return ret; |
| 763 | 1052 | } |
| 764 | 1053 | |
| @@ -766,7 +1055,7 @@ static int imx290_start_streaming(struct imx290 *imx290, · 1 unmodified line | ||
| 766 | 1055 | format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0); |
| 767 | 1056 | ret = imx290_setup_format(imx290, format); |
| 768 | 1057 | if (ret < 0) { |
| 769 | − dev_err(imx290->dev, "Could not set frame format\n"); | |
| 1058 | + dev_err(imx290->dev, "Could not set frame format - %d\n", ret); | |
| 770 | 1059 | return ret; |
| 771 | 1060 | } |
| 772 | 1061 | |
| @@ -774,19 +1063,14 @@ static int imx290_start_streaming(struct imx290 *imx290, · 1 unmodified line | ||
| 774 | 1063 | ret = imx290_set_register_array(imx290, imx290->current_mode->data, |
| 775 | 1064 | imx290->current_mode->data_size); |
| 776 | 1065 | if (ret < 0) { |
| 777 | − dev_err(imx290->dev, "Could not set current mode\n"); | |
| 1066 | + dev_err(imx290->dev, "Could not set current mode - %d\n", ret); | |
| 778 | 1067 | return ret; |
| 779 | 1068 | } |
| 780 | 1069 | |
| 781 | − ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax, | |
| 782 | − NULL); | |
| 783 | − if (ret) | |
| 784 | − return ret; | |
| 785 | − | |
| 786 | 1070 | /* Apply customized values from user */ |
| 787 | 1071 | ret = __v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); |
| 788 | 1072 | if (ret) { |
| 789 | − dev_err(imx290->dev, "Could not sync v4l2 controls\n"); | |
| 1073 | + dev_err(imx290->dev, "Could not sync v4l2 controls - %d\n", ret); | |
| 790 | 1074 | return ret; |
| 791 | 1075 | } |
| 792 | 1076 | |
| @@ -835,6 +1119,13 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable) · 42 unmodified lines | ||
| 835 | 1119 | pm_runtime_put_autosuspend(imx290->dev); |
| 836 | 1120 | } |
| 837 | 1121 | |
| 1122 | + /* | |
| 1123 | + * vflip and hflip should not be changed during streaming as the sensor | |
| 1124 | + * will produce an invalid frame. | |
| 1125 | + */ | |
| 1126 | + __v4l2_ctrl_grab(imx290->vflip, enable); | |
| 1127 | + __v4l2_ctrl_grab(imx290->hflip, enable); | |
| 1128 | + | |
| 838 | 1129 | unlock: |
| 839 | 1130 | v4l2_subdev_unlock_state(state); |
| 840 | 1131 | return ret; |
| @@ -844,10 +1135,12 @@ static int imx290_enum_mbus_code(struct v4l2_subdev *sd, · 3 unmodified lines | ||
| 844 | 1135 | struct v4l2_subdev_state *sd_state, |
| 845 | 1136 | struct v4l2_subdev_mbus_code_enum *code) |
| 846 | 1137 | { |
| 1138 | + const struct imx290 *imx290 = to_imx290(sd); | |
| 1139 | + | |
| 847 | 1140 | if (code->index >= ARRAY_SIZE(imx290_formats)) |
| 848 | 1141 | return -EINVAL; |
| 849 | 1142 | |
| 850 | − code->code = imx290_formats[code->index].code; | |
| 1143 | + code->code = imx290_formats[code->index].code[imx290->model->colour_variant]; | |
| 851 | 1144 | |
| 852 | 1145 | return 0; |
| 853 | 1146 | } |
| @@ -859,7 +1152,7 @@ static int imx290_enum_frame_size(struct v4l2_subdev *sd, · 5 unmodified lines | ||
| 859 | 1152 | const struct imx290 *imx290 = to_imx290(sd); |
| 860 | 1153 | const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); |
| 861 | 1154 | |
| 862 | − if (!imx290_format_info(fse->code)) | |
| 1155 | + if (!imx290_format_info(imx290, fse->code)) | |
| 863 | 1156 | return -EINVAL; |
| 864 | 1157 | |
| 865 | 1158 | if (fse->index >= imx290_modes_num(imx290)) |
| @@ -888,10 +1181,14 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, · 22 unmodified lines | ||
| 888 | 1181 | fmt->format.width = mode->width; |
| 889 | 1182 | fmt->format.height = mode->height; |
| 890 | 1183 | |
| 891 | − if (!imx290_format_info(fmt->format.code)) | |
| 892 | − fmt->format.code = imx290_formats[0].code; | |
| 1184 | + if (!imx290_format_info(imx290, fmt->format.code)) | |
| 1185 | + fmt->format.code = imx290_formats[0].code[imx290->model->colour_variant]; | |
| 893 | 1186 | |
| 894 | 1187 | fmt->format.field = V4L2_FIELD_NONE; |
| 1188 | + fmt->format.colorspace = V4L2_COLORSPACE_RAW; | |
| 1189 | + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601; | |
| 1190 | + fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; | |
| 1191 | + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; | |
| 895 | 1192 | |
| 896 | 1193 | format = v4l2_subdev_get_pad_format(sd, sd_state, 0); |
| 897 | 1194 | |
| @@ -899,6 +1196,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, · 1 unmodified line | ||
| 899 | 1196 | imx290->current_mode = mode; |
| 900 | 1197 | |
| 901 | 1198 | imx290_ctrl_update(imx290, &fmt->format, mode); |
| 1199 | + imx290_exposure_update(imx290, mode); | |
| 902 | 1200 | } |
| 903 | 1201 | |
| 904 | 1202 | *format = fmt->format; |
| @@ -910,16 +1208,23 @@ static int imx290_get_selection(struct v4l2_subdev *sd, · 5 unmodified lines | ||
| 910 | 1208 | struct v4l2_subdev_state *sd_state, |
| 911 | 1209 | struct v4l2_subdev_selection *sel) |
| 912 | 1210 | { |
| 1211 | + struct imx290 *imx290 = to_imx290(sd); | |
| 913 | 1212 | struct v4l2_mbus_framefmt *format; |
| 914 | 1213 | |
| 915 | 1214 | switch (sel->target) { |
| 916 | 1215 | case V4L2_SEL_TGT_CROP: { |
| 917 | 1216 | format = v4l2_subdev_get_pad_format(sd, sd_state, 0); |
| 918 | 1217 | |
| 1218 | + /* | |
| 1219 | + * The sensor moves the readout by 1 pixel based on flips to | |
| 1220 | + * keep the Bayer order the same. | |
| 1221 | + */ | |
| 919 | 1222 | sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP |
| 920 | − + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2; | |
| 1223 | + + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2 | |
| 1224 | + + imx290->vflip->val; | |
| 921 | 1225 | sel->r.left = IMX920_PIXEL_ARRAY_MARGIN_LEFT |
| 922 | − + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2; | |
| 1226 | + + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2 | |
| 1227 | + + imx290->hflip->val; | |
| 923 | 1228 | sel->r.width = format->width; |
| 924 | 1229 | sel->r.height = format->height; |
| 925 | 1230 | |
| @@ -964,6 +1269,11 @@ static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, · 38 unmodified lines | ||
| 964 | 1269 | return 0; |
| 965 | 1270 | } |
| 966 | 1271 | |
| 1272 | +static const struct v4l2_subdev_core_ops imx290_core_ops = { | |
| 1273 | + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, | |
| 1274 | + .unsubscribe_event = v4l2_event_subdev_unsubscribe, | |
| 1275 | +}; | |
| 1276 | + | |
| 967 | 1277 | static const struct v4l2_subdev_video_ops imx290_video_ops = { |
| 968 | 1278 | .s_stream = imx290_set_stream, |
| 969 | 1279 | }; |
| @@ -978,6 +1288,7 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = { · 8 unmodified lines | ||
| 978 | 1288 | }; |
| 979 | 1289 | |
| 980 | 1290 | static const struct v4l2_subdev_ops imx290_subdev_ops = { |
| 1291 | + .core = &imx290_core_ops, | |
| 981 | 1292 | .video = &imx290_video_ops, |
| 982 | 1293 | .pad = &imx290_pad_ops, |
| 983 | 1294 | }; |
| @@ -996,7 +1307,8 @@ static int imx290_subdev_init(struct imx290 *imx290) · 12 unmodified lines | ||
| 996 | 1307 | imx290->current_mode = &imx290_modes_ptr(imx290)[0]; |
| 997 | 1308 | |
| 998 | 1309 | v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); |
| 999 | − imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1310 | + imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | |
| 1311 | + V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 1000 | 1312 | imx290->sd.dev = imx290->dev; |
| 1001 | 1313 | imx290->sd.entity.ops = &imx290_subdev_entity_ops; |
| 1002 | 1314 | imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; |
| @@ -1132,15 +1444,22 @@ static int imx290_init_clk(struct imx290 *imx290) · 129 unmodified lines | ||
| 1132 | 1444 | u32 xclk_freq; |
| 1133 | 1445 | int ret; |
| 1134 | 1446 | |
| 1135 | − ret = fwnode_property_read_u32(dev_fwnode(imx290->dev), | |
| 1136 | − "clock-frequency", &xclk_freq); | |
| 1447 | + ret = device_property_read_u32(imx290->dev, "clock-frequency", | |
| 1448 | + &xclk_freq); | |
| 1137 | 1449 | if (ret) { |
| 1138 | 1450 | dev_err(imx290->dev, "Could not get xclk frequency\n"); |
| 1139 | 1451 | return ret; |
| 1140 | 1452 | } |
| 1141 | 1453 | |
| 1142 | − /* external clock must be 37.125 MHz */ | |
| 1143 | − if (xclk_freq != 37125000) { | |
| 1454 | + /* external clock must be 37.125 MHz or 74.25MHz */ | |
| 1455 | + switch (xclk_freq) { | |
| 1456 | + case 37125000: | |
| 1457 | + imx290->xclk_idx = IMX290_CLK_37_125; | |
| 1458 | + break; | |
| 1459 | + case 74250000: | |
| 1460 | + imx290->xclk_idx = IMX290_CLK_74_25; | |
| 1461 | + break; | |
| 1462 | + default: | |
| 1144 | 1463 | dev_err(imx290->dev, "External clock frequency %u is not supported\n", |
| 1145 | 1464 | xclk_freq); |
| 1146 | 1465 | return -EINVAL; |
| @@ -1177,6 +1496,27 @@ static s64 imx290_check_link_freqs(const struct imx290 *imx290, · 30 unmodified lines | ||
| 1177 | 1496 | return 0; |
| 1178 | 1497 | } |
| 1179 | 1498 | |
| 1499 | +static const struct imx290_model_info imx290_models[] = { | |
| 1500 | + [IMX290_MODEL_IMX290LQR] = { | |
| 1501 | + .colour_variant = IMX290_VARIANT_COLOUR, | |
| 1502 | + .init_regs = imx290_global_init_settings_290, | |
| 1503 | + .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290), | |
| 1504 | + .name = "imx290", | |
| 1505 | + }, | |
| 1506 | + [IMX290_MODEL_IMX290LLR] = { | |
| 1507 | + .colour_variant = IMX290_VARIANT_MONO, | |
| 1508 | + .init_regs = imx290_global_init_settings_290, | |
| 1509 | + .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290), | |
| 1510 | + .name = "imx290", | |
| 1511 | + }, | |
| 1512 | + [IMX290_MODEL_IMX327LQR] = { | |
| 1513 | + .colour_variant = IMX290_VARIANT_COLOUR, | |
| 1514 | + .init_regs = imx290_global_init_settings_327, | |
| 1515 | + .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_327), | |
| 1516 | + .name = "imx327", | |
| 1517 | + }, | |
| 1518 | +}; | |
| 1519 | + | |
| 1180 | 1520 | static int imx290_parse_dt(struct imx290 *imx290) |
| 1181 | 1521 | { |
| 1182 | 1522 | /* Only CSI2 is supported for now: */ |
| @@ -1187,6 +1527,8 @@ static int imx290_parse_dt(struct imx290 *imx290) · 4 unmodified lines | ||
| 1187 | 1527 | int ret; |
| 1188 | 1528 | s64 fq; |
| 1189 | 1529 | |
| 1530 | + imx290->model = of_device_get_match_data(imx290->dev); | |
| 1531 | + | |
| 1190 | 1532 | endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx290->dev), NULL); |
| 1191 | 1533 | if (!endpoint) { |
| 1192 | 1534 | dev_err(imx290->dev, "Endpoint node not found\n"); |
| @@ -1260,7 +1602,7 @@ static int imx290_probe(struct i2c_client *client) · 67 unmodified lines | ||
| 1260 | 1602 | imx290->xclk = devm_clk_get(dev, "xclk"); |
| 1261 | 1603 | if (IS_ERR(imx290->xclk)) |
| 1262 | 1604 | return dev_err_probe(dev, PTR_ERR(imx290->xclk), |
| 1263 | − "Could not get xclk"); | |
| 1605 | + "Could not get xclk\n"); | |
| 1264 | 1606 | |
| 1265 | 1607 | ret = imx290_get_regulators(dev, imx290); |
| 1266 | 1608 | if (ret < 0) |
| @@ -1304,6 +1646,9 @@ static int imx290_probe(struct i2c_client *client) · 37 unmodified lines | ||
| 1304 | 1646 | if (ret) |
| 1305 | 1647 | goto err_pm; |
| 1306 | 1648 | |
| 1649 | + v4l2_i2c_subdev_set_name(&imx290->sd, client, | |
| 1650 | + imx290->model->name, NULL); | |
| 1651 | + | |
| 1307 | 1652 | /* |
| 1308 | 1653 | * Finally, register the V4L2 subdev. This must be done after |
| 1309 | 1654 | * initializing everything as the subdev can be used immediately after |
| @@ -1352,8 +1697,21 @@ static void imx290_remove(struct i2c_client *client) · 42 unmodified lines | ||
| 1352 | 1697 | } |
| 1353 | 1698 | |
| 1354 | 1699 | static const struct of_device_id imx290_of_match[] = { |
| 1355 | − { .compatible = "sony,imx290" }, | |
| 1356 | − { /* sentinel */ } | |
| 1700 | + { | |
| 1701 | + /* Deprecated - synonym for "sony,imx290lqr" */ | |
| 1702 | + .compatible = "sony,imx290", | |
| 1703 | + .data = &imx290_models[IMX290_MODEL_IMX290LQR], | |
| 1704 | + }, { | |
| 1705 | + .compatible = "sony,imx290lqr", | |
| 1706 | + .data = &imx290_models[IMX290_MODEL_IMX290LQR], | |
| 1707 | + }, { | |
| 1708 | + .compatible = "sony,imx290llr", | |
| 1709 | + .data = &imx290_models[IMX290_MODEL_IMX290LLR], | |
| 1710 | + }, { | |
| 1711 | + .compatible = "sony,imx327lqr", | |
| 1712 | + .data = &imx290_models[IMX290_MODEL_IMX327LQR], | |
| 1713 | + }, | |
| 1714 | + { /* sentinel */ }, | |
| 1357 | 1715 | }; |
| 1358 | 1716 | MODULE_DEVICE_TABLE(of, imx290_of_match); |
| 1359 | 1717 | |
| @@ -685,15 +685,6 @@ static int imx296_enum_frame_size(struct v4l2_subdev *sd, · 684 unmodified lines | ||
| 685 | 685 | return 0; |
| 686 | 686 | } |
| 687 | 687 | |
| 688 | −static int imx296_get_format(struct v4l2_subdev *sd, | |
| 689 | − struct v4l2_subdev_state *state, | |
| 690 | − struct v4l2_subdev_format *fmt) | |
| 691 | −{ | |
| 692 | − fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad); | |
| 693 | − | |
| 694 | − return 0; | |
| 695 | −} | |
| 696 | − | |
| 697 | 688 | static int imx296_set_format(struct v4l2_subdev *sd, |
| 698 | 689 | struct v4l2_subdev_state *state, |
| 699 | 690 | struct v4l2_subdev_format *fmt) |
| @@ -845,7 +836,7 @@ static const struct v4l2_subdev_video_ops imx296_subdev_video_ops = { · 145 unmodified lines | ||
| 845 | 836 | static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = { |
| 846 | 837 | .enum_mbus_code = imx296_enum_mbus_code, |
| 847 | 838 | .enum_frame_size = imx296_enum_frame_size, |
| 848 | − .get_fmt = imx296_get_format, | |
| 839 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 849 | 840 | .set_fmt = imx296_set_format, |
| 850 | 841 | .get_selection = imx296_get_selection, |
| 851 | 842 | .set_selection = imx296_set_selection, |
| @@ -79,7 +79,6 @@ struct imx334_reg_list { · 78 unmodified lines | ||
| 79 | 79 | * struct imx334_mode - imx334 sensor mode structure |
| 80 | 80 | * @width: Frame width |
| 81 | 81 | * @height: Frame height |
| 82 | − * @code: Format code | |
| 83 | 82 | * @hblank: Horizontal blanking in lines |
| 84 | 83 | * @vblank: Vertical blanking in lines |
| 85 | 84 | * @vblank_min: Minimal vertical blanking in lines |
| @@ -91,7 +90,6 @@ struct imx334_reg_list { · 5 unmodified lines | ||
| 91 | 90 | struct imx334_mode { |
| 92 | 91 | u32 width; |
| 93 | 92 | u32 height; |
| 94 | − u32 code; | |
| 95 | 93 | u32 hblank; |
| 96 | 94 | u32 vblank; |
| 97 | 95 | u32 vblank_min; |
| @@ -119,6 +117,7 @@ struct imx334_mode { · 21 unmodified lines | ||
| 119 | 117 | * @vblank: Vertical blanking in lines |
| 120 | 118 | * @cur_mode: Pointer to current selected sensor mode |
| 121 | 119 | * @mutex: Mutex for serializing sensor controls |
| 120 | + * @cur_code: current selected format code | |
| 122 | 121 | * @streaming: Flag indicating streaming state |
| 123 | 122 | */ |
| 124 | 123 | struct imx334 { |
| @@ -140,6 +139,7 @@ struct imx334 { · 15 unmodified lines | ||
| 140 | 139 | u32 vblank; |
| 141 | 140 | const struct imx334_mode *cur_mode; |
| 142 | 141 | struct mutex mutex; |
| 142 | + u32 cur_code; | |
| 143 | 143 | bool streaming; |
| 144 | 144 | }; |
| 145 | 145 | |
| @@ -147,7 +147,170 @@ static const s64 link_freq[] = { · 1 unmodified line | ||
| 147 | 147 | IMX334_LINK_FREQ, |
| 148 | 148 | }; |
| 149 | 149 | |
| 150 | −/* Sensor mode registers */ | |
| 150 | +/* Sensor mode registers for 1920x1080@30fps */ | |
| 151 | +static const struct imx334_reg mode_1920x1080_regs[] = { | |
| 152 | + {0x3000, 0x01}, | |
| 153 | + {0x3018, 0x04}, | |
| 154 | + {0x3030, 0xca}, | |
| 155 | + {0x3031, 0x08}, | |
| 156 | + {0x3032, 0x00}, | |
| 157 | + {0x3034, 0x4c}, | |
| 158 | + {0x3035, 0x04}, | |
| 159 | + {0x302c, 0xf0}, | |
| 160 | + {0x302d, 0x03}, | |
| 161 | + {0x302e, 0x80}, | |
| 162 | + {0x302f, 0x07}, | |
| 163 | + {0x3074, 0xcc}, | |
| 164 | + {0x3075, 0x02}, | |
| 165 | + {0x308e, 0xcd}, | |
| 166 | + {0x308f, 0x02}, | |
| 167 | + {0x3076, 0x38}, | |
| 168 | + {0x3077, 0x04}, | |
| 169 | + {0x3090, 0x38}, | |
| 170 | + {0x3091, 0x04}, | |
| 171 | + {0x3308, 0x38}, | |
| 172 | + {0x3309, 0x04}, | |
| 173 | + {0x30C6, 0x00}, | |
| 174 | + {0x30c7, 0x00}, | |
| 175 | + {0x30ce, 0x00}, | |
| 176 | + {0x30cf, 0x00}, | |
| 177 | + {0x30d8, 0x18}, | |
| 178 | + {0x30d9, 0x0a}, | |
| 179 | + {0x304c, 0x00}, | |
| 180 | + {0x304e, 0x00}, | |
| 181 | + {0x304f, 0x00}, | |
| 182 | + {0x3050, 0x00}, | |
| 183 | + {0x30b6, 0x00}, | |
| 184 | + {0x30b7, 0x00}, | |
| 185 | + {0x3116, 0x08}, | |
| 186 | + {0x3117, 0x00}, | |
| 187 | + {0x31a0, 0x20}, | |
| 188 | + {0x31a1, 0x0f}, | |
| 189 | + {0x300c, 0x3b}, | |
| 190 | + {0x300d, 0x29}, | |
| 191 | + {0x314c, 0x29}, | |
| 192 | + {0x314d, 0x01}, | |
| 193 | + {0x315a, 0x06}, | |
| 194 | + {0x3168, 0xa0}, | |
| 195 | + {0x316a, 0x7e}, | |
| 196 | + {0x319e, 0x02}, | |
| 197 | + {0x3199, 0x00}, | |
| 198 | + {0x319d, 0x00}, | |
| 199 | + {0x31dd, 0x03}, | |
| 200 | + {0x3300, 0x00}, | |
| 201 | + {0x341c, 0xff}, | |
| 202 | + {0x341d, 0x01}, | |
| 203 | + {0x3a01, 0x03}, | |
| 204 | + {0x3a18, 0x7f}, | |
| 205 | + {0x3a19, 0x00}, | |
| 206 | + {0x3a1a, 0x37}, | |
| 207 | + {0x3a1b, 0x00}, | |
| 208 | + {0x3a1c, 0x37}, | |
| 209 | + {0x3a1d, 0x00}, | |
| 210 | + {0x3a1e, 0xf7}, | |
| 211 | + {0x3a1f, 0x00}, | |
| 212 | + {0x3a20, 0x3f}, | |
| 213 | + {0x3a21, 0x00}, | |
| 214 | + {0x3a20, 0x6f}, | |
| 215 | + {0x3a21, 0x00}, | |
| 216 | + {0x3a20, 0x3f}, | |
| 217 | + {0x3a21, 0x00}, | |
| 218 | + {0x3a20, 0x5f}, | |
| 219 | + {0x3a21, 0x00}, | |
| 220 | + {0x3a20, 0x2f}, | |
| 221 | + {0x3a21, 0x00}, | |
| 222 | + {0x3078, 0x02}, | |
| 223 | + {0x3079, 0x00}, | |
| 224 | + {0x307a, 0x00}, | |
| 225 | + {0x307b, 0x00}, | |
| 226 | + {0x3080, 0x02}, | |
| 227 | + {0x3081, 0x00}, | |
| 228 | + {0x3082, 0x00}, | |
| 229 | + {0x3083, 0x00}, | |
| 230 | + {0x3088, 0x02}, | |
| 231 | + {0x3094, 0x00}, | |
| 232 | + {0x3095, 0x00}, | |
| 233 | + {0x3096, 0x00}, | |
| 234 | + {0x309b, 0x02}, | |
| 235 | + {0x309c, 0x00}, | |
| 236 | + {0x309d, 0x00}, | |
| 237 | + {0x309e, 0x00}, | |
| 238 | + {0x30a4, 0x00}, | |
| 239 | + {0x30a5, 0x00}, | |
| 240 | + {0x3288, 0x21}, | |
| 241 | + {0x328a, 0x02}, | |
| 242 | + {0x3414, 0x05}, | |
| 243 | + {0x3416, 0x18}, | |
| 244 | + {0x35Ac, 0x0e}, | |
| 245 | + {0x3648, 0x01}, | |
| 246 | + {0x364a, 0x04}, | |
| 247 | + {0x364c, 0x04}, | |
| 248 | + {0x3678, 0x01}, | |
| 249 | + {0x367c, 0x31}, | |
| 250 | + {0x367e, 0x31}, | |
| 251 | + {0x3708, 0x02}, | |
| 252 | + {0x3714, 0x01}, | |
| 253 | + {0x3715, 0x02}, | |
| 254 | + {0x3716, 0x02}, | |
| 255 | + {0x3717, 0x02}, | |
| 256 | + {0x371c, 0x3d}, | |
| 257 | + {0x371d, 0x3f}, | |
| 258 | + {0x372c, 0x00}, | |
| 259 | + {0x372d, 0x00}, | |
| 260 | + {0x372e, 0x46}, | |
| 261 | + {0x372f, 0x00}, | |
| 262 | + {0x3730, 0x89}, | |
| 263 | + {0x3731, 0x00}, | |
| 264 | + {0x3732, 0x08}, | |
| 265 | + {0x3733, 0x01}, | |
| 266 | + {0x3734, 0xfe}, | |
| 267 | + {0x3735, 0x05}, | |
| 268 | + {0x375d, 0x00}, | |
| 269 | + {0x375e, 0x00}, | |
| 270 | + {0x375f, 0x61}, | |
| 271 | + {0x3760, 0x06}, | |
| 272 | + {0x3768, 0x1b}, | |
| 273 | + {0x3769, 0x1b}, | |
| 274 | + {0x376a, 0x1a}, | |
| 275 | + {0x376b, 0x19}, | |
| 276 | + {0x376c, 0x18}, | |
| 277 | + {0x376d, 0x14}, | |
| 278 | + {0x376e, 0x0f}, | |
| 279 | + {0x3776, 0x00}, | |
| 280 | + {0x3777, 0x00}, | |
| 281 | + {0x3778, 0x46}, | |
| 282 | + {0x3779, 0x00}, | |
| 283 | + {0x377a, 0x08}, | |
| 284 | + {0x377b, 0x01}, | |
| 285 | + {0x377c, 0x45}, | |
| 286 | + {0x377d, 0x01}, | |
| 287 | + {0x377e, 0x23}, | |
| 288 | + {0x377f, 0x02}, | |
| 289 | + {0x3780, 0xd9}, | |
| 290 | + {0x3781, 0x03}, | |
| 291 | + {0x3782, 0xf5}, | |
| 292 | + {0x3783, 0x06}, | |
| 293 | + {0x3784, 0xa5}, | |
| 294 | + {0x3788, 0x0f}, | |
| 295 | + {0x378a, 0xd9}, | |
| 296 | + {0x378b, 0x03}, | |
| 297 | + {0x378c, 0xeb}, | |
| 298 | + {0x378d, 0x05}, | |
| 299 | + {0x378e, 0x87}, | |
| 300 | + {0x378f, 0x06}, | |
| 301 | + {0x3790, 0xf5}, | |
| 302 | + {0x3792, 0x43}, | |
| 303 | + {0x3794, 0x7a}, | |
| 304 | + {0x3796, 0xa1}, | |
| 305 | + {0x37b0, 0x37}, | |
| 306 | + {0x3e04, 0x0e}, | |
| 307 | + {0x30e8, 0x50}, | |
| 308 | + {0x30e9, 0x00}, | |
| 309 | + {0x3e04, 0x0e}, | |
| 310 | + {0x3002, 0x00}, | |
| 311 | +}; | |
| 312 | + | |
| 313 | +/* Sensor mode registers for 3840x2160@30fps */ | |
| 151 | 314 | static const struct imx334_reg mode_3840x2160_regs[] = { |
| 152 | 315 | {0x3000, 0x01}, |
| 153 | 316 | {0x3002, 0x00}, |
| @@ -166,6 +329,7 @@ static const struct imx334_reg mode_3840x2160_regs[] = { · 12 unmodified lines | ||
| 166 | 329 | {0x3288, 0x21}, |
| 167 | 330 | {0x328a, 0x02}, |
| 168 | 331 | {0x302c, 0x3c}, |
| 332 | + {0x302d, 0x00}, | |
| 169 | 333 | {0x302e, 0x00}, |
| 170 | 334 | {0x302f, 0x0f}, |
| 171 | 335 | {0x3076, 0x70}, |
| @@ -240,23 +404,75 @@ static const struct imx334_reg mode_3840x2160_regs[] = { · 68 unmodified lines | ||
| 240 | 404 | {0x3794, 0x7a}, |
| 241 | 405 | {0x3796, 0xa1}, |
| 242 | 406 | {0x3e04, 0x0e}, |
| 407 | + {0x319e, 0x00}, | |
| 243 | 408 | {0x3a00, 0x01}, |
| 409 | + {0x3a18, 0xbf}, | |
| 410 | + {0x3a19, 0x00}, | |
| 411 | + {0x3a1a, 0x67}, | |
| 412 | + {0x3a1b, 0x00}, | |
| 413 | + {0x3a1c, 0x6f}, | |
| 414 | + {0x3a1d, 0x00}, | |
| 415 | + {0x3a1e, 0xd7}, | |
| 416 | + {0x3a1f, 0x01}, | |
| 417 | + {0x3a20, 0x6f}, | |
| 418 | + {0x3a21, 0x00}, | |
| 419 | + {0x3a22, 0xcf}, | |
| 420 | + {0x3a23, 0x00}, | |
| 421 | + {0x3a24, 0x6f}, | |
| 422 | + {0x3a25, 0x00}, | |
| 423 | + {0x3a26, 0xb7}, | |
| 424 | + {0x3a27, 0x00}, | |
| 425 | + {0x3a28, 0x5f}, | |
| 426 | + {0x3a29, 0x00}, | |
| 427 | +}; | |
| 428 | + | |
| 429 | +static const struct imx334_reg raw10_framefmt_regs[] = { | |
| 430 | + {0x3050, 0x00}, | |
| 431 | + {0x319d, 0x00}, | |
| 432 | + {0x341c, 0xff}, | |
| 433 | + {0x341d, 0x01}, | |
| 434 | +}; | |
| 435 | + | |
| 436 | +static const struct imx334_reg raw12_framefmt_regs[] = { | |
| 437 | + {0x3050, 0x01}, | |
| 438 | + {0x319d, 0x01}, | |
| 439 | + {0x341c, 0x47}, | |
| 440 | + {0x341d, 0x00}, | |
| 441 | +}; | |
| 442 | + | |
| 443 | +static const u32 imx334_mbus_codes[] = { | |
| 444 | + MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 445 | + MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 244 | 446 | }; |
| 245 | 447 | |
| 246 | 448 | /* Supported sensor mode configurations */ |
| 247 | −static const struct imx334_mode supported_mode = { | |
| 248 | − .width = 3840, | |
| 249 | − .height = 2160, | |
| 250 | − .hblank = 560, | |
| 251 | − .vblank = 2340, | |
| 252 | − .vblank_min = 90, | |
| 253 | − .vblank_max = 132840, | |
| 254 | − .pclk = 594000000, | |
| 255 | − .link_freq_idx = 0, | |
| 256 | − .code = MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 257 | − .reg_list = { | |
| 258 | − .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs), | |
| 259 | − .regs = mode_3840x2160_regs, | |
| 449 | +static const struct imx334_mode supported_modes[] = { | |
| 450 | + { | |
| 451 | + .width = 3840, | |
| 452 | + .height = 2160, | |
| 453 | + .hblank = 560, | |
| 454 | + .vblank = 2340, | |
| 455 | + .vblank_min = 90, | |
| 456 | + .vblank_max = 132840, | |
| 457 | + .pclk = 594000000, | |
| 458 | + .link_freq_idx = 0, | |
| 459 | + .reg_list = { | |
| 460 | + .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs), | |
| 461 | + .regs = mode_3840x2160_regs, | |
| 462 | + }, | |
| 463 | + }, { | |
| 464 | + .width = 1920, | |
| 465 | + .height = 1080, | |
| 466 | + .hblank = 2480, | |
| 467 | + .vblank = 1170, | |
| 468 | + .vblank_min = 45, | |
| 469 | + .vblank_max = 132840, | |
| 470 | + .pclk = 297000000, | |
| 471 | + .link_freq_idx = 0, | |
| 472 | + .reg_list = { | |
| 473 | + .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), | |
| 474 | + .regs = mode_1920x1080_regs, | |
| 475 | + }, | |
| 260 | 476 | }, |
| 261 | 477 | }; |
| 262 | 478 | |
| @@ -382,7 +598,8 @@ static int imx334_update_controls(struct imx334 *imx334, · 119 unmodified lines | ||
| 382 | 598 | if (ret) |
| 383 | 599 | return ret; |
| 384 | 600 | |
| 385 | − ret = __v4l2_ctrl_s_ctrl(imx334->hblank_ctrl, mode->hblank); | |
| 601 | + ret = __v4l2_ctrl_modify_range(imx334->hblank_ctrl, mode->hblank, | |
| 602 | + mode->hblank, 1, mode->hblank); | |
| 386 | 603 | if (ret) |
| 387 | 604 | return ret; |
| 388 | 605 | |
| @@ -480,6 +697,9 @@ static int imx334_set_ctrl(struct v4l2_ctrl *ctrl) · 91 unmodified lines | ||
| 480 | 697 | |
| 481 | 698 | pm_runtime_put(imx334->dev); |
| 482 | 699 | |
| 700 | + break; | |
| 701 | + case V4L2_CID_HBLANK: | |
| 702 | + ret = 0; | |
| 483 | 703 | break; |
| 484 | 704 | default: |
| 485 | 705 | dev_err(imx334->dev, "Invalid control %d", ctrl->id); |
| @@ -494,6 +714,18 @@ static const struct v4l2_ctrl_ops imx334_ctrl_ops = { · 8 unmodified lines | ||
| 494 | 714 | .s_ctrl = imx334_set_ctrl, |
| 495 | 715 | }; |
| 496 | 716 | |
| 717 | +static int imx334_get_format_code(struct imx334 *imx334, u32 code) | |
| 718 | +{ | |
| 719 | + unsigned int i; | |
| 720 | + | |
| 721 | + for (i = 0; i < ARRAY_SIZE(imx334_mbus_codes); i++) { | |
| 722 | + if (imx334_mbus_codes[i] == code) | |
| 723 | + return imx334_mbus_codes[i]; | |
| 724 | + } | |
| 725 | + | |
| 726 | + return imx334_mbus_codes[0]; | |
| 727 | +} | |
| 728 | + | |
| 497 | 729 | /** |
| 498 | 730 | * imx334_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes |
| 499 | 731 | * @sd: pointer to imx334 V4L2 sub-device structure |
| @@ -506,10 +738,10 @@ static int imx334_enum_mbus_code(struct v4l2_subdev *sd, · 6 unmodified lines | ||
| 506 | 738 | struct v4l2_subdev_state *sd_state, |
| 507 | 739 | struct v4l2_subdev_mbus_code_enum *code) |
| 508 | 740 | { |
| 509 | − if (code->index > 0) | |
| 741 | + if (code->index >= ARRAY_SIZE(imx334_mbus_codes)) | |
| 510 | 742 | return -EINVAL; |
| 511 | 743 | |
| 512 | − code->code = supported_mode.code; | |
| 744 | + code->code = imx334_mbus_codes[code->index]; | |
| 513 | 745 | |
| 514 | 746 | return 0; |
| 515 | 747 | } |
| @@ -526,15 +758,20 @@ static int imx334_enum_frame_size(struct v4l2_subdev *sd, · 10 unmodified lines | ||
| 526 | 758 | struct v4l2_subdev_state *sd_state, |
| 527 | 759 | struct v4l2_subdev_frame_size_enum *fsize) |
| 528 | 760 | { |
| 529 | − if (fsize->index > 0) | |
| 761 | + struct imx334 *imx334 = to_imx334(sd); | |
| 762 | + u32 code; | |
| 763 | + | |
| 764 | + if (fsize->index >= ARRAY_SIZE(supported_modes)) | |
| 530 | 765 | return -EINVAL; |
| 531 | 766 | |
| 532 | − if (fsize->code != supported_mode.code) | |
| 767 | + code = imx334_get_format_code(imx334, fsize->code); | |
| 768 | + | |
| 769 | + if (fsize->code != code) | |
| 533 | 770 | return -EINVAL; |
| 534 | 771 | |
| 535 | − fsize->min_width = supported_mode.width; | |
| 772 | + fsize->min_width = supported_modes[fsize->index].width; | |
| 536 | 773 | fsize->max_width = fsize->min_width; |
| 537 | − fsize->min_height = supported_mode.height; | |
| 774 | + fsize->min_height = supported_modes[fsize->index].height; | |
| 538 | 775 | fsize->max_height = fsize->min_height; |
| 539 | 776 | |
| 540 | 777 | return 0; |
| @@ -553,7 +790,6 @@ static void imx334_fill_pad_format(struct imx334 *imx334, · 12 unmodified lines | ||
| 553 | 790 | { |
| 554 | 791 | fmt->format.width = mode->width; |
| 555 | 792 | fmt->format.height = mode->height; |
| 556 | − fmt->format.code = mode->code; | |
| 557 | 793 | fmt->format.field = V4L2_FIELD_NONE; |
| 558 | 794 | fmt->format.colorspace = V4L2_COLORSPACE_RAW; |
| 559 | 795 | fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
| @@ -583,6 +819,7 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd, · 23 unmodified lines | ||
| 583 | 819 | framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); |
| 584 | 820 | fmt->format = *framefmt; |
| 585 | 821 | } else { |
| 822 | + fmt->format.code = imx334->cur_code; | |
| 586 | 823 | imx334_fill_pad_format(imx334, imx334->cur_mode, fmt); |
| 587 | 824 | } |
| 588 | 825 | |
| @@ -609,15 +846,21 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd, · 20 unmodified lines | ||
| 609 | 846 | |
| 610 | 847 | mutex_lock(&imx334->mutex); |
| 611 | 848 | |
| 612 | − mode = &supported_mode; | |
| 849 | + mode = v4l2_find_nearest_size(supported_modes, | |
| 850 | + ARRAY_SIZE(supported_modes), | |
| 851 | + width, height, | |
| 852 | + fmt->format.width, fmt->format.height); | |
| 853 | + | |
| 613 | 854 | imx334_fill_pad_format(imx334, mode, fmt); |
| 855 | + fmt->format.code = imx334_get_format_code(imx334, fmt->format.code); | |
| 614 | 856 | |
| 615 | 857 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 616 | 858 | struct v4l2_mbus_framefmt *framefmt; |
| 617 | 859 | |
| 618 | 860 | framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); |
| 619 | 861 | *framefmt = fmt->format; |
| 620 | − } else { | |
| 862 | + } else if (imx334->cur_mode != mode || imx334->cur_code != fmt->format.code) { | |
| 863 | + imx334->cur_code = fmt->format.code; | |
| 621 | 864 | ret = imx334_update_controls(imx334, mode); |
| 622 | 865 | if (!ret) |
| 623 | 866 | imx334->cur_mode = mode; |
| @@ -642,11 +885,26 @@ static int imx334_init_pad_cfg(struct v4l2_subdev *sd, · 18 unmodified lines | ||
| 642 | 885 | struct v4l2_subdev_format fmt = { 0 }; |
| 643 | 886 | |
| 644 | 887 | fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; |
| 645 | − imx334_fill_pad_format(imx334, &supported_mode, &fmt); | |
| 888 | + imx334_fill_pad_format(imx334, &supported_modes[0], &fmt); | |
| 646 | 889 | |
| 647 | 890 | return imx334_set_pad_format(sd, sd_state, &fmt); |
| 648 | 891 | } |
| 649 | 892 | |
| 893 | +static int imx334_set_framefmt(struct imx334 *imx334) | |
| 894 | +{ | |
| 895 | + switch (imx334->cur_code) { | |
| 896 | + case MEDIA_BUS_FMT_SRGGB10_1X10: | |
| 897 | + return imx334_write_regs(imx334, raw10_framefmt_regs, | |
| 898 | + ARRAY_SIZE(raw10_framefmt_regs)); | |
| 899 | + | |
| 900 | + case MEDIA_BUS_FMT_SRGGB12_1X12: | |
| 901 | + return imx334_write_regs(imx334, raw12_framefmt_regs, | |
| 902 | + ARRAY_SIZE(raw12_framefmt_regs)); | |
| 903 | + } | |
| 904 | + | |
| 905 | + return -EINVAL; | |
| 906 | +} | |
| 907 | + | |
| 650 | 908 | /** |
| 651 | 909 | * imx334_start_streaming() - Start sensor stream |
| 652 | 910 | * @imx334: pointer to imx334 device |
| @@ -667,6 +925,13 @@ static int imx334_start_streaming(struct imx334 *imx334) · 14 unmodified lines | ||
| 667 | 925 | return ret; |
| 668 | 926 | } |
| 669 | 927 | |
| 928 | + ret = imx334_set_framefmt(imx334); | |
| 929 | + if (ret) { | |
| 930 | + dev_err(imx334->dev, "%s failed to set frame format: %d\n", | |
| 931 | + __func__, ret); | |
| 932 | + return ret; | |
| 933 | + } | |
| 934 | + | |
| 670 | 935 | /* Setup handler will write actual exposure and gain */ |
| 671 | 936 | ret = __v4l2_ctrl_handler_setup(imx334->sd.ctrl_handler); |
| 672 | 937 | if (ret) { |
| @@ -1037,7 +1302,8 @@ static int imx334_probe(struct i2c_client *client) · 364 unmodified lines | ||
| 1037 | 1302 | } |
| 1038 | 1303 | |
| 1039 | 1304 | /* Set default mode to max resolution */ |
| 1040 | − imx334->cur_mode = &supported_mode; | |
| 1305 | + imx334->cur_mode = &supported_modes[0]; | |
| 1306 | + imx334->cur_code = imx334_mbus_codes[0]; | |
| 1041 | 1307 | imx334->vblank = imx334->cur_mode->vblank; |
| 1042 | 1308 | |
| 1043 | 1309 | ret = imx334_init_controls(imx334); |
| @@ -1,8 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −config VIDEO_M5MOLS | |
| 3 | − tristate "Fujitsu M-5MOLS 8MP sensor support" | |
| 4 | − depends on I2C && VIDEO_DEV | |
| 5 | − select MEDIA_CONTROLLER | |
| 6 | − select VIDEO_V4L2_SUBDEV_API | |
| 7 | − help | |
| 8 | − This driver supports Fujitsu M-5MOLS camera sensor with ISP | |
| @@ -1,4 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o | |
| 3 | − | |
| 4 | −obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o | |
| @@ -1,349 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * Header for M-5MOLS 8M Pixel camera sensor with ISP | |
| 4 | − * | |
| 5 | − * Copyright (C) 2011 Samsung Electronics Co., Ltd. | |
| 6 | − * Author: HeungJun Kim <riverful.kim@samsung.com> | |
| 7 | − * | |
| 8 | − * Copyright (C) 2009 Samsung Electronics Co., Ltd. | |
| 9 | − * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#ifndef M5MOLS_H | |
| 13 | −#define M5MOLS_H | |
| 14 | − | |
| 15 | −#include <linux/sizes.h> | |
| 16 | −#include <linux/gpio/consumer.h> | |
| 17 | −#include <media/v4l2-subdev.h> | |
| 18 | −#include "m5mols_reg.h" | |
| 19 | − | |
| 20 | − | |
| 21 | −/* An amount of data transmitted in addition to the value | |
| 22 | − * determined by CAPP_JPEG_SIZE_MAX register. | |
| 23 | − */ | |
| 24 | −#define M5MOLS_JPEG_TAGS_SIZE 0x20000 | |
| 25 | −#define M5MOLS_MAIN_JPEG_SIZE_MAX (5 * SZ_1M) | |
| 26 | − | |
| 27 | −extern int m5mols_debug; | |
| 28 | − | |
| 29 | −enum m5mols_restype { | |
| 30 | − M5MOLS_RESTYPE_MONITOR, | |
| 31 | − M5MOLS_RESTYPE_CAPTURE, | |
| 32 | − M5MOLS_RESTYPE_MAX, | |
| 33 | −}; | |
| 34 | − | |
| 35 | −/** | |
| 36 | − * struct m5mols_resolution - structure for the resolution | |
| 37 | − * @type: resolution type according to the pixel code | |
| 38 | − * @width: width of the resolution | |
| 39 | − * @height: height of the resolution | |
| 40 | − * @reg: resolution preset register value | |
| 41 | − */ | |
| 42 | −struct m5mols_resolution { | |
| 43 | − u8 reg; | |
| 44 | − enum m5mols_restype type; | |
| 45 | − u16 width; | |
| 46 | − u16 height; | |
| 47 | −}; | |
| 48 | − | |
| 49 | −/** | |
| 50 | − * struct m5mols_exif - structure for the EXIF information of M-5MOLS | |
| 51 | − * @exposure_time: exposure time register value | |
| 52 | − * @shutter_speed: speed of the shutter register value | |
| 53 | − * @aperture: aperture register value | |
| 54 | − * @brightness: brightness register value | |
| 55 | − * @exposure_bias: it calls also EV bias | |
| 56 | − * @iso_speed: ISO register value | |
| 57 | − * @flash: status register value of the flash | |
| 58 | − * @sdr: status register value of the Subject Distance Range | |
| 59 | − * @qval: not written exact meaning in document | |
| 60 | − */ | |
| 61 | −struct m5mols_exif { | |
| 62 | − u32 exposure_time; | |
| 63 | − u32 shutter_speed; | |
| 64 | − u32 aperture; | |
| 65 | − u32 brightness; | |
| 66 | − u32 exposure_bias; | |
| 67 | − u16 iso_speed; | |
| 68 | − u16 flash; | |
| 69 | − u16 sdr; | |
| 70 | − u16 qval; | |
| 71 | −}; | |
| 72 | − | |
| 73 | −/** | |
| 74 | − * struct m5mols_capture - Structure for the capture capability | |
| 75 | − * @exif: EXIF information | |
| 76 | − * @buf_size: internal JPEG frame buffer size, in bytes | |
| 77 | − * @main: size in bytes of the main image | |
| 78 | − * @thumb: size in bytes of the thumb image, if it was accompanied | |
| 79 | − * @total: total size in bytes of the produced image | |
| 80 | − */ | |
| 81 | −struct m5mols_capture { | |
| 82 | − struct m5mols_exif exif; | |
| 83 | − unsigned int buf_size; | |
| 84 | − u32 main; | |
| 85 | − u32 thumb; | |
| 86 | − u32 total; | |
| 87 | −}; | |
| 88 | − | |
| 89 | −/** | |
| 90 | − * struct m5mols_scenemode - structure for the scenemode capability | |
| 91 | − * @metering: metering light register value | |
| 92 | − * @ev_bias: EV bias register value | |
| 93 | − * @wb_mode: mode which means the WhiteBalance is Auto or Manual | |
| 94 | − * @wb_preset: whitebalance preset register value in the Manual mode | |
| 95 | − * @chroma_en: register value whether the Chroma capability is enabled or not | |
| 96 | − * @chroma_lvl: chroma's level register value | |
| 97 | − * @edge_en: register value Whether the Edge capability is enabled or not | |
| 98 | − * @edge_lvl: edge's level register value | |
| 99 | − * @af_range: Auto Focus's range | |
| 100 | − * @fd_mode: Face Detection mode | |
| 101 | − * @mcc: Multi-axis Color Conversion which means emotion color | |
| 102 | − * @light: status of the Light | |
| 103 | − * @flash: status of the Flash | |
| 104 | − * @tone: Tone color which means Contrast | |
| 105 | − * @iso: ISO register value | |
| 106 | − * @capt_mode: Mode of the Image Stabilization while the camera capturing | |
| 107 | − * @wdr: Wide Dynamic Range register value | |
| 108 | − * | |
| 109 | − * The each value according to each scenemode is recommended in the documents. | |
| 110 | − */ | |
| 111 | −struct m5mols_scenemode { | |
| 112 | − u8 metering; | |
| 113 | − u8 ev_bias; | |
| 114 | − u8 wb_mode; | |
| 115 | − u8 wb_preset; | |
| 116 | − u8 chroma_en; | |
| 117 | − u8 chroma_lvl; | |
| 118 | − u8 edge_en; | |
| 119 | − u8 edge_lvl; | |
| 120 | − u8 af_range; | |
| 121 | − u8 fd_mode; | |
| 122 | − u8 mcc; | |
| 123 | − u8 light; | |
| 124 | − u8 flash; | |
| 125 | − u8 tone; | |
| 126 | − u8 iso; | |
| 127 | − u8 capt_mode; | |
| 128 | − u8 wdr; | |
| 129 | −}; | |
| 130 | − | |
| 131 | −#define VERSION_STRING_SIZE 22 | |
| 132 | − | |
| 133 | −/** | |
| 134 | − * struct m5mols_version - firmware version information | |
| 135 | − * @customer: customer information | |
| 136 | − * @project: version of project information according to customer | |
| 137 | − * @fw: firmware revision | |
| 138 | − * @hw: hardware revision | |
| 139 | − * @param: version of the parameter | |
| 140 | − * @awb: Auto WhiteBalance algorithm version | |
| 141 | − * @str: information about manufacturer and packaging vendor | |
| 142 | − * @af: Auto Focus version | |
| 143 | − * | |
| 144 | − * The register offset starts the customer version at 0x0, and it ends | |
| 145 | − * the awb version at 0x09. The customer, project information occupies 1 bytes | |
| 146 | − * each. And also the fw, hw, param, awb each requires 2 bytes. The str is | |
| 147 | − * unique string associated with firmware's version. It includes information | |
| 148 | − * about manufacturer and the vendor of the sensor's packaging. The least | |
| 149 | − * significant 2 bytes of the string indicate packaging manufacturer. | |
| 150 | − */ | |
| 151 | −struct m5mols_version { | |
| 152 | − u8 customer; | |
| 153 | − u8 project; | |
| 154 | − u16 fw; | |
| 155 | − u16 hw; | |
| 156 | − u16 param; | |
| 157 | − u16 awb; | |
| 158 | − u8 str[VERSION_STRING_SIZE]; | |
| 159 | − u8 af; | |
| 160 | −}; | |
| 161 | − | |
| 162 | −/** | |
| 163 | − * struct m5mols_info - M-5MOLS driver data structure | |
| 164 | − * @pdata: platform data | |
| 165 | − * @sd: v4l-subdev instance | |
| 166 | − * @pad: media pad | |
| 167 | − * @irq_waitq: waitqueue for the capture | |
| 168 | − * @irq_done: set to 1 in the interrupt handler | |
| 169 | − * @handle: control handler | |
| 170 | − * @auto_exposure: auto/manual exposure control | |
| 171 | − * @exposure_bias: exposure compensation control | |
| 172 | − * @exposure: manual exposure control | |
| 173 | − * @metering: exposure metering control | |
| 174 | − * @auto_iso: auto/manual ISO sensitivity control | |
| 175 | − * @iso: manual ISO sensitivity control | |
| 176 | − * @auto_wb: auto white balance control | |
| 177 | − * @lock_3a: 3A lock control | |
| 178 | − * @colorfx: color effect control | |
| 179 | − * @saturation: saturation control | |
| 180 | − * @zoom: zoom control | |
| 181 | − * @wdr: wide dynamic range control | |
| 182 | − * @stabilization: image stabilization control | |
| 183 | − * @jpeg_quality: JPEG compression quality control | |
| 184 | − * @set_power: optional power callback to the board code | |
| 185 | − * @reset: GPIO driving the reset pin of M-5MOLS | |
| 186 | − * @lock: mutex protecting the structure fields below | |
| 187 | − * @ffmt: current fmt according to resolution type | |
| 188 | − * @res_type: current resolution type | |
| 189 | − * @ver: information of the version | |
| 190 | − * @cap: the capture mode attributes | |
| 191 | − * @isp_ready: 1 when the ISP controller has completed booting | |
| 192 | − * @power: current sensor's power status | |
| 193 | − * @ctrl_sync: 1 when the control handler state is restored in H/W | |
| 194 | − * @resolution: register value for current resolution | |
| 195 | − * @mode: register value for current operation mode | |
| 196 | − */ | |
| 197 | −struct m5mols_info { | |
| 198 | − const struct m5mols_platform_data *pdata; | |
| 199 | − struct v4l2_subdev sd; | |
| 200 | − struct media_pad pad; | |
| 201 | − | |
| 202 | − wait_queue_head_t irq_waitq; | |
| 203 | − atomic_t irq_done; | |
| 204 | − | |
| 205 | − struct v4l2_ctrl_handler handle; | |
| 206 | − struct { | |
| 207 | − /* exposure/exposure bias/auto exposure cluster */ | |
| 208 | − struct v4l2_ctrl *auto_exposure; | |
| 209 | − struct v4l2_ctrl *exposure_bias; | |
| 210 | − struct v4l2_ctrl *exposure; | |
| 211 | − struct v4l2_ctrl *metering; | |
| 212 | − }; | |
| 213 | − struct { | |
| 214 | − /* iso/auto iso cluster */ | |
| 215 | − struct v4l2_ctrl *auto_iso; | |
| 216 | − struct v4l2_ctrl *iso; | |
| 217 | − }; | |
| 218 | − struct v4l2_ctrl *auto_wb; | |
| 219 | − | |
| 220 | − struct v4l2_ctrl *lock_3a; | |
| 221 | − struct v4l2_ctrl *colorfx; | |
| 222 | − struct v4l2_ctrl *saturation; | |
| 223 | − struct v4l2_ctrl *zoom; | |
| 224 | − struct v4l2_ctrl *wdr; | |
| 225 | − struct v4l2_ctrl *stabilization; | |
| 226 | − struct v4l2_ctrl *jpeg_quality; | |
| 227 | − | |
| 228 | − int (*set_power)(struct device *dev, int on); | |
| 229 | − struct gpio_desc *reset; | |
| 230 | − | |
| 231 | − struct mutex lock; | |
| 232 | − | |
| 233 | − struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; | |
| 234 | − int res_type; | |
| 235 | − | |
| 236 | − struct m5mols_version ver; | |
| 237 | − struct m5mols_capture cap; | |
| 238 | − | |
| 239 | − unsigned int isp_ready:1; | |
| 240 | − unsigned int power:1; | |
| 241 | − unsigned int ctrl_sync:1; | |
| 242 | − | |
| 243 | − u8 resolution; | |
| 244 | − u8 mode; | |
| 245 | −}; | |
| 246 | − | |
| 247 | −#define is_available_af(__info) (__info->ver.af) | |
| 248 | −#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) | |
| 249 | −#define is_manufacturer(__info, __manufacturer) \ | |
| 250 | − (__info->ver.str[0] == __manufacturer[0] && \ | |
| 251 | − __info->ver.str[1] == __manufacturer[1]) | |
| 252 | −/* | |
| 253 | − * I2C operation of the M-5MOLS | |
| 254 | − * | |
| 255 | − * The I2C read operation of the M-5MOLS requires 2 messages. The first | |
| 256 | − * message sends the information about the command, command category, and total | |
| 257 | − * message size. The second message is used to retrieve the data specified in | |
| 258 | − * the first message | |
| 259 | − * | |
| 260 | − * 1st message 2nd message | |
| 261 | − * +-------+---+----------+-----+-------+ +------+------+------+------+ | |
| 262 | − * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] | | |
| 263 | − * +-------+---+----------+-----+-------+ +------+------+------+------+ | |
| 264 | − * - size1: message data size(5 in this case) | |
| 265 | − * - size2: desired buffer size of the 2nd message | |
| 266 | − * - d[0..3]: according to size2 | |
| 267 | − * | |
| 268 | − * The I2C write operation needs just one message. The message includes | |
| 269 | − * category, command, total size, and desired data. | |
| 270 | − * | |
| 271 | − * 1st message | |
| 272 | − * +-------+---+----------+-----+------+------+------+------+ | |
| 273 | − * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] | | |
| 274 | − * +-------+---+----------+-----+------+------+------+------+ | |
| 275 | − * - d[0..3]: according to size1 | |
| 276 | − */ | |
| 277 | −int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); | |
| 278 | −int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); | |
| 279 | −int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); | |
| 280 | −int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); | |
| 281 | − | |
| 282 | −int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, | |
| 283 | − int timeout); | |
| 284 | − | |
| 285 | −/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */ | |
| 286 | −#define M5MOLS_I2C_RDY_WAIT_FL (1 << 16) | |
| 287 | −/* ISP state transition timeout, in ms */ | |
| 288 | −#define M5MOLS_MODE_CHANGE_TIMEOUT 200 | |
| 289 | −#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT 250 | |
| 290 | − | |
| 291 | −/* | |
| 292 | − * Mode operation of the M-5MOLS | |
| 293 | − * | |
| 294 | − * Changing the mode of the M-5MOLS is needed right executing order. | |
| 295 | − * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed | |
| 296 | − * by user. There are various categories associated with each mode. | |
| 297 | − * | |
| 298 | − * +============================================================+ | |
| 299 | − * | mode | category | | |
| 300 | − * +============================================================+ | |
| 301 | − * | FLASH | FLASH(only after Stand-by or Power-on) | | |
| 302 | − * | SYSTEM | SYSTEM(only after sensor arm-booting) | | |
| 303 | − * | PARAMETER | PARAMETER | | |
| 304 | − * | MONITOR | MONITOR(preview), Auto Focus, Face Detection | | |
| 305 | − * | CAPTURE | Single CAPTURE, Preview(recording) | | |
| 306 | − * +============================================================+ | |
| 307 | − * | |
| 308 | − * The available executing order between each modes are as follows: | |
| 309 | − * PARAMETER <---> MONITOR <---> CAPTURE | |
| 310 | − */ | |
| 311 | −int m5mols_set_mode(struct m5mols_info *info, u8 mode); | |
| 312 | − | |
| 313 | −int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); | |
| 314 | −int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout); | |
| 315 | −int m5mols_restore_controls(struct m5mols_info *info); | |
| 316 | −int m5mols_start_capture(struct m5mols_info *info); | |
| 317 | −int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); | |
| 318 | −int m5mols_lock_3a(struct m5mols_info *info, bool lock); | |
| 319 | −int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); | |
| 320 | −int m5mols_init_controls(struct v4l2_subdev *sd); | |
| 321 | − | |
| 322 | −/* The firmware function */ | |
| 323 | −int m5mols_update_fw(struct v4l2_subdev *sd, | |
| 324 | − int (*set_power)(struct m5mols_info *, bool)); | |
| 325 | − | |
| 326 | −static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *subdev) | |
| 327 | −{ | |
| 328 | − return container_of(subdev, struct m5mols_info, sd); | |
| 329 | −} | |
| 330 | − | |
| 331 | −static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | |
| 332 | −{ | |
| 333 | − struct m5mols_info *info = container_of(ctrl->handler, | |
| 334 | − struct m5mols_info, handle); | |
| 335 | − return &info->sd; | |
| 336 | −} | |
| 337 | − | |
| 338 | −static inline void m5mols_set_ctrl_mode(struct v4l2_ctrl *ctrl, | |
| 339 | − unsigned int mode) | |
| 340 | −{ | |
| 341 | − ctrl->priv = (void *)(uintptr_t)mode; | |
| 342 | −} | |
| 343 | − | |
| 344 | −static inline unsigned int m5mols_get_ctrl_mode(struct v4l2_ctrl *ctrl) | |
| 345 | −{ | |
| 346 | − return (unsigned int)(uintptr_t)ctrl->priv; | |
| 347 | −} | |
| 348 | − | |
| 349 | −#endif /* M5MOLS_H */ | |
| @@ -1,158 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | − | |
| 3 | −/* | |
| 4 | − * The Capture code for Fujitsu M-5MOLS ISP | |
| 5 | − * | |
| 6 | − * Copyright (C) 2011 Samsung Electronics Co., Ltd. | |
| 7 | − * Author: HeungJun Kim <riverful.kim@samsung.com> | |
| 8 | − * | |
| 9 | − * Copyright (C) 2009 Samsung Electronics Co., Ltd. | |
| 10 | − * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | |
| 11 | − */ | |
| 12 | − | |
| 13 | −#include <linux/i2c.h> | |
| 14 | −#include <linux/slab.h> | |
| 15 | −#include <linux/irq.h> | |
| 16 | −#include <linux/interrupt.h> | |
| 17 | −#include <linux/delay.h> | |
| 18 | −#include <linux/regulator/consumer.h> | |
| 19 | −#include <linux/videodev2.h> | |
| 20 | −#include <media/v4l2-ctrls.h> | |
| 21 | −#include <media/v4l2-device.h> | |
| 22 | −#include <media/v4l2-subdev.h> | |
| 23 | −#include <media/i2c/m5mols.h> | |
| 24 | −#include <media/drv-intf/exynos-fimc.h> | |
| 25 | − | |
| 26 | −#include "m5mols.h" | |
| 27 | −#include "m5mols_reg.h" | |
| 28 | − | |
| 29 | −/** | |
| 30 | − * m5mols_read_rational - I2C read of a rational number | |
| 31 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 32 | − * @addr_num: numerator register | |
| 33 | − * @addr_den: denominator register | |
| 34 | − * @val: place to store the division result | |
| 35 | − * | |
| 36 | − * Read numerator and denominator from registers @addr_num and @addr_den | |
| 37 | − * respectively and return the division result in @val. | |
| 38 | − */ | |
| 39 | −static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, | |
| 40 | − u32 addr_den, u32 *val) | |
| 41 | −{ | |
| 42 | − u32 num, den; | |
| 43 | − | |
| 44 | − int ret = m5mols_read_u32(sd, addr_num, &num); | |
| 45 | − if (!ret) | |
| 46 | − ret = m5mols_read_u32(sd, addr_den, &den); | |
| 47 | − if (ret) | |
| 48 | − return ret; | |
| 49 | − *val = den == 0 ? 0 : num / den; | |
| 50 | − return ret; | |
| 51 | −} | |
| 52 | − | |
| 53 | −/** | |
| 54 | − * m5mols_capture_info - Gather captured image information | |
| 55 | − * @info: M-5MOLS driver data structure | |
| 56 | − * | |
| 57 | − * For now it gathers only EXIF information and file size. | |
| 58 | − */ | |
| 59 | −static int m5mols_capture_info(struct m5mols_info *info) | |
| 60 | −{ | |
| 61 | − struct m5mols_exif *exif = &info->cap.exif; | |
| 62 | − struct v4l2_subdev *sd = &info->sd; | |
| 63 | − int ret; | |
| 64 | − | |
| 65 | − ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU, | |
| 66 | − EXIF_INFO_EXPTIME_DE, &exif->exposure_time); | |
| 67 | − if (ret) | |
| 68 | − return ret; | |
| 69 | − ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE, | |
| 70 | − &exif->shutter_speed); | |
| 71 | − if (ret) | |
| 72 | − return ret; | |
| 73 | − ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE, | |
| 74 | − &exif->aperture); | |
| 75 | − if (ret) | |
| 76 | − return ret; | |
| 77 | − ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE, | |
| 78 | − &exif->brightness); | |
| 79 | − if (ret) | |
| 80 | − return ret; | |
| 81 | − ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE, | |
| 82 | − &exif->exposure_bias); | |
| 83 | − if (ret) | |
| 84 | − return ret; | |
| 85 | − | |
| 86 | − ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed); | |
| 87 | − if (!ret) | |
| 88 | − ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash); | |
| 89 | − if (!ret) | |
| 90 | − ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr); | |
| 91 | − if (!ret) | |
| 92 | − ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval); | |
| 93 | − if (ret) | |
| 94 | − return ret; | |
| 95 | − | |
| 96 | − if (!ret) | |
| 97 | − ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main); | |
| 98 | − if (!ret) | |
| 99 | − ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb); | |
| 100 | − if (!ret) | |
| 101 | − info->cap.total = info->cap.main + info->cap.thumb; | |
| 102 | − | |
| 103 | − return ret; | |
| 104 | −} | |
| 105 | − | |
| 106 | −int m5mols_start_capture(struct m5mols_info *info) | |
| 107 | −{ | |
| 108 | − unsigned int framesize = info->cap.buf_size - M5MOLS_JPEG_TAGS_SIZE; | |
| 109 | − struct v4l2_subdev *sd = &info->sd; | |
| 110 | − int ret; | |
| 111 | − | |
| 112 | − /* | |
| 113 | − * Synchronize the controls, set the capture frame resolution and color | |
| 114 | − * format. The frame capture is initiated during switching from Monitor | |
| 115 | − * to Capture mode. | |
| 116 | − */ | |
| 117 | − ret = m5mols_set_mode(info, REG_MONITOR); | |
| 118 | − if (!ret) | |
| 119 | − ret = m5mols_restore_controls(info); | |
| 120 | − if (!ret) | |
| 121 | − ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); | |
| 122 | − if (!ret) | |
| 123 | − ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution); | |
| 124 | − if (!ret) | |
| 125 | − ret = m5mols_write(sd, CAPP_JPEG_SIZE_MAX, framesize); | |
| 126 | − if (!ret) | |
| 127 | − ret = m5mols_set_mode(info, REG_CAPTURE); | |
| 128 | − if (!ret) | |
| 129 | − /* Wait until a frame is captured to ISP internal memory */ | |
| 130 | − ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); | |
| 131 | − if (ret) | |
| 132 | − return ret; | |
| 133 | − | |
| 134 | − /* | |
| 135 | − * Initiate the captured data transfer to a MIPI-CSI receiver. | |
| 136 | − */ | |
| 137 | − ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); | |
| 138 | − if (!ret) | |
| 139 | − ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); | |
| 140 | − if (!ret) { | |
| 141 | − bool captured = false; | |
| 142 | − unsigned int size; | |
| 143 | − | |
| 144 | − /* Wait for the capture completion interrupt */ | |
| 145 | − ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); | |
| 146 | − if (!ret) { | |
| 147 | − captured = true; | |
| 148 | − ret = m5mols_capture_info(info); | |
| 149 | − } | |
| 150 | − size = captured ? info->cap.main : 0; | |
| 151 | − v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n", | |
| 152 | − __func__, size, info->cap.thumb); | |
| 153 | − | |
| 154 | − v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size); | |
| 155 | − } | |
| 156 | − | |
| 157 | − return ret; | |
| 158 | −} | |
| @@ -1,625 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * Controls for M-5MOLS 8M Pixel camera sensor with ISP | |
| 4 | − * | |
| 5 | − * Copyright (C) 2011 Samsung Electronics Co., Ltd. | |
| 6 | − * Author: HeungJun Kim <riverful.kim@samsung.com> | |
| 7 | − * | |
| 8 | − * Copyright (C) 2009 Samsung Electronics Co., Ltd. | |
| 9 | − * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#include <linux/i2c.h> | |
| 13 | −#include <linux/delay.h> | |
| 14 | −#include <linux/videodev2.h> | |
| 15 | −#include <media/v4l2-ctrls.h> | |
| 16 | − | |
| 17 | −#include "m5mols.h" | |
| 18 | −#include "m5mols_reg.h" | |
| 19 | − | |
| 20 | −static struct m5mols_scenemode m5mols_default_scenemode[] = { | |
| 21 | − [REG_SCENE_NORMAL] = { | |
| 22 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 23 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 24 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 25 | − REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 26 | − 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 27 | − }, | |
| 28 | − [REG_SCENE_PORTRAIT] = { | |
| 29 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 30 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 4, | |
| 31 | − REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME, | |
| 32 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 33 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 34 | − }, | |
| 35 | − [REG_SCENE_LANDSCAPE] = { | |
| 36 | − REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 37 | − REG_CHROMA_ON, 4, REG_EDGE_ON, 6, | |
| 38 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 39 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 40 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 41 | − }, | |
| 42 | − [REG_SCENE_SPORTS] = { | |
| 43 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 44 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 45 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 46 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 47 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 48 | − }, | |
| 49 | − [REG_SCENE_PARTY_INDOOR] = { | |
| 50 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 51 | − REG_CHROMA_ON, 4, REG_EDGE_ON, 5, | |
| 52 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 53 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 54 | − 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF, | |
| 55 | − }, | |
| 56 | − [REG_SCENE_BEACH_SNOW] = { | |
| 57 | − REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0, | |
| 58 | − REG_CHROMA_ON, 4, REG_EDGE_ON, 5, | |
| 59 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 60 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 61 | − 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, | |
| 62 | − }, | |
| 63 | − [REG_SCENE_SUNSET] = { | |
| 64 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, | |
| 65 | − REG_AWB_DAYLIGHT, | |
| 66 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 67 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 68 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 69 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 70 | − }, | |
| 71 | − [REG_SCENE_DAWN_DUSK] = { | |
| 72 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, | |
| 73 | − REG_AWB_FLUORESCENT_1, | |
| 74 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 75 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 76 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 77 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 78 | − }, | |
| 79 | − [REG_SCENE_FALL] = { | |
| 80 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 81 | − REG_CHROMA_ON, 5, REG_EDGE_ON, 5, | |
| 82 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 83 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 84 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 85 | − }, | |
| 86 | − [REG_SCENE_NIGHT] = { | |
| 87 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 88 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 89 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 90 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 91 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 92 | − }, | |
| 93 | − [REG_SCENE_AGAINST_LIGHT] = { | |
| 94 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 95 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 96 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 97 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 98 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 99 | − }, | |
| 100 | − [REG_SCENE_FIRE] = { | |
| 101 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 102 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 103 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 104 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 105 | − 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, | |
| 106 | − }, | |
| 107 | − [REG_SCENE_TEXT] = { | |
| 108 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 109 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 7, | |
| 110 | − REG_AF_MACRO, REG_FD_OFF, | |
| 111 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 112 | − 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON, | |
| 113 | − }, | |
| 114 | − [REG_SCENE_CANDLE] = { | |
| 115 | − REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | |
| 116 | − REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | |
| 117 | − REG_AF_NORMAL, REG_FD_OFF, | |
| 118 | − REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | |
| 119 | − 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | |
| 120 | − }, | |
| 121 | −}; | |
| 122 | − | |
| 123 | −/** | |
| 124 | − * m5mols_do_scenemode() - Change current scenemode | |
| 125 | − * @info: M-5MOLS driver data structure | |
| 126 | − * @mode: Desired mode of the scenemode | |
| 127 | − * | |
| 128 | − * WARNING: The execution order is important. Do not change the order. | |
| 129 | − */ | |
| 130 | −int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) | |
| 131 | −{ | |
| 132 | − struct v4l2_subdev *sd = &info->sd; | |
| 133 | − struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; | |
| 134 | − int ret; | |
| 135 | − | |
| 136 | − if (mode > REG_SCENE_CANDLE) | |
| 137 | − return -EINVAL; | |
| 138 | − | |
| 139 | − ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0); | |
| 140 | − if (!ret) | |
| 141 | − ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode); | |
| 142 | − if (!ret) | |
| 143 | − ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode); | |
| 144 | − if (!ret) | |
| 145 | − ret = m5mols_write(sd, AE_MODE, scenemode.metering); | |
| 146 | − if (!ret) | |
| 147 | − ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias); | |
| 148 | − if (!ret) | |
| 149 | − ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode); | |
| 150 | − if (!ret) | |
| 151 | − ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset); | |
| 152 | − if (!ret) | |
| 153 | − ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en); | |
| 154 | − if (!ret) | |
| 155 | − ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl); | |
| 156 | − if (!ret) | |
| 157 | − ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en); | |
| 158 | − if (!ret) | |
| 159 | − ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl); | |
| 160 | − if (!ret && is_available_af(info)) | |
| 161 | − ret = m5mols_write(sd, AF_MODE, scenemode.af_range); | |
| 162 | − if (!ret && is_available_af(info)) | |
| 163 | − ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode); | |
| 164 | − if (!ret) | |
| 165 | − ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone); | |
| 166 | − if (!ret) | |
| 167 | − ret = m5mols_write(sd, AE_ISO, scenemode.iso); | |
| 168 | − if (!ret) | |
| 169 | − ret = m5mols_set_mode(info, REG_CAPTURE); | |
| 170 | − if (!ret) | |
| 171 | − ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); | |
| 172 | − if (!ret) | |
| 173 | − ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc); | |
| 174 | − if (!ret) | |
| 175 | − ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light); | |
| 176 | − if (!ret) | |
| 177 | − ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash); | |
| 178 | − if (!ret) | |
| 179 | − ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); | |
| 180 | − if (!ret) | |
| 181 | − ret = m5mols_set_mode(info, REG_MONITOR); | |
| 182 | − | |
| 183 | − return ret; | |
| 184 | −} | |
| 185 | − | |
| 186 | −static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl) | |
| 187 | −{ | |
| 188 | − bool af_lock = ctrl->val & V4L2_LOCK_FOCUS; | |
| 189 | − int ret = 0; | |
| 190 | − | |
| 191 | − if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) { | |
| 192 | − bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; | |
| 193 | − | |
| 194 | − ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ? | |
| 195 | − REG_AE_LOCK : REG_AE_UNLOCK); | |
| 196 | − if (ret) | |
| 197 | − return ret; | |
| 198 | − } | |
| 199 | − | |
| 200 | − if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE) | |
| 201 | − && info->auto_wb->val) { | |
| 202 | − bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; | |
| 203 | − | |
| 204 | − ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ? | |
| 205 | − REG_AWB_LOCK : REG_AWB_UNLOCK); | |
| 206 | − if (ret) | |
| 207 | − return ret; | |
| 208 | − } | |
| 209 | − | |
| 210 | − if (!info->ver.af || !af_lock) | |
| 211 | − return ret; | |
| 212 | − | |
| 213 | − if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS) | |
| 214 | − ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); | |
| 215 | − | |
| 216 | − return ret; | |
| 217 | −} | |
| 218 | − | |
| 219 | −static int m5mols_set_metering_mode(struct m5mols_info *info, int mode) | |
| 220 | −{ | |
| 221 | − unsigned int metering; | |
| 222 | − | |
| 223 | − switch (mode) { | |
| 224 | − case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: | |
| 225 | − metering = REG_AE_CENTER; | |
| 226 | − break; | |
| 227 | − case V4L2_EXPOSURE_METERING_SPOT: | |
| 228 | − metering = REG_AE_SPOT; | |
| 229 | − break; | |
| 230 | − default: | |
| 231 | − metering = REG_AE_ALL; | |
| 232 | − break; | |
| 233 | − } | |
| 234 | − | |
| 235 | − return m5mols_write(&info->sd, AE_MODE, metering); | |
| 236 | −} | |
| 237 | − | |
| 238 | −static int m5mols_set_exposure(struct m5mols_info *info, int exposure) | |
| 239 | −{ | |
| 240 | − struct v4l2_subdev *sd = &info->sd; | |
| 241 | − int ret = 0; | |
| 242 | − | |
| 243 | − if (exposure == V4L2_EXPOSURE_AUTO) { | |
| 244 | − /* Unlock auto exposure */ | |
| 245 | − info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE; | |
| 246 | − m5mols_3a_lock(info, info->lock_3a); | |
| 247 | − | |
| 248 | − ret = m5mols_set_metering_mode(info, info->metering->val); | |
| 249 | − if (ret < 0) | |
| 250 | − return ret; | |
| 251 | − | |
| 252 | − v4l2_dbg(1, m5mols_debug, sd, | |
| 253 | − "%s: exposure bias: %#x, metering: %#x\n", | |
| 254 | − __func__, info->exposure_bias->val, | |
| 255 | − info->metering->val); | |
| 256 | − | |
| 257 | − return m5mols_write(sd, AE_INDEX, info->exposure_bias->val); | |
| 258 | − } | |
| 259 | − | |
| 260 | − if (exposure == V4L2_EXPOSURE_MANUAL) { | |
| 261 | − ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); | |
| 262 | − if (ret == 0) | |
| 263 | − ret = m5mols_write(sd, AE_MAN_GAIN_MON, | |
| 264 | − info->exposure->val); | |
| 265 | − if (ret == 0) | |
| 266 | − ret = m5mols_write(sd, AE_MAN_GAIN_CAP, | |
| 267 | − info->exposure->val); | |
| 268 | − | |
| 269 | − v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n", | |
| 270 | − __func__, info->exposure->val); | |
| 271 | − } | |
| 272 | − | |
| 273 | − return ret; | |
| 274 | −} | |
| 275 | − | |
| 276 | −static int m5mols_set_white_balance(struct m5mols_info *info, int val) | |
| 277 | −{ | |
| 278 | − static const unsigned short wb[][2] = { | |
| 279 | − { V4L2_WHITE_BALANCE_INCANDESCENT, REG_AWB_INCANDESCENT }, | |
| 280 | − { V4L2_WHITE_BALANCE_FLUORESCENT, REG_AWB_FLUORESCENT_1 }, | |
| 281 | − { V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 }, | |
| 282 | − { V4L2_WHITE_BALANCE_HORIZON, REG_AWB_HORIZON }, | |
| 283 | − { V4L2_WHITE_BALANCE_DAYLIGHT, REG_AWB_DAYLIGHT }, | |
| 284 | − { V4L2_WHITE_BALANCE_FLASH, REG_AWB_LEDLIGHT }, | |
| 285 | − { V4L2_WHITE_BALANCE_CLOUDY, REG_AWB_CLOUDY }, | |
| 286 | − { V4L2_WHITE_BALANCE_SHADE, REG_AWB_SHADE }, | |
| 287 | − { V4L2_WHITE_BALANCE_AUTO, REG_AWB_AUTO }, | |
| 288 | − }; | |
| 289 | − int i; | |
| 290 | − struct v4l2_subdev *sd = &info->sd; | |
| 291 | − int ret = -EINVAL; | |
| 292 | − | |
| 293 | − for (i = 0; i < ARRAY_SIZE(wb); i++) { | |
| 294 | − int awb; | |
| 295 | − if (wb[i][0] != val) | |
| 296 | − continue; | |
| 297 | − | |
| 298 | − v4l2_dbg(1, m5mols_debug, sd, | |
| 299 | − "Setting white balance to: %#x\n", wb[i][0]); | |
| 300 | − | |
| 301 | − awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO; | |
| 302 | − ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO : | |
| 303 | − REG_AWB_PRESET); | |
| 304 | − if (ret < 0) | |
| 305 | − return ret; | |
| 306 | − | |
| 307 | − if (!awb) | |
| 308 | − ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]); | |
| 309 | − } | |
| 310 | − | |
| 311 | − return ret; | |
| 312 | −} | |
| 313 | − | |
| 314 | −static int m5mols_set_saturation(struct m5mols_info *info, int val) | |
| 315 | −{ | |
| 316 | − int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val); | |
| 317 | − if (ret < 0) | |
| 318 | − return ret; | |
| 319 | − | |
| 320 | − return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON); | |
| 321 | −} | |
| 322 | − | |
| 323 | −static int m5mols_set_color_effect(struct m5mols_info *info, int val) | |
| 324 | −{ | |
| 325 | − unsigned int m_effect = REG_COLOR_EFFECT_OFF; | |
| 326 | − unsigned int p_effect = REG_EFFECT_OFF; | |
| 327 | − unsigned int cfix_r = 0, cfix_b = 0; | |
| 328 | − struct v4l2_subdev *sd = &info->sd; | |
| 329 | − int ret = 0; | |
| 330 | − | |
| 331 | − switch (val) { | |
| 332 | − case V4L2_COLORFX_BW: | |
| 333 | − m_effect = REG_COLOR_EFFECT_ON; | |
| 334 | − break; | |
| 335 | − case V4L2_COLORFX_NEGATIVE: | |
| 336 | − p_effect = REG_EFFECT_NEGA; | |
| 337 | − break; | |
| 338 | − case V4L2_COLORFX_EMBOSS: | |
| 339 | − p_effect = REG_EFFECT_EMBOSS; | |
| 340 | − break; | |
| 341 | − case V4L2_COLORFX_SEPIA: | |
| 342 | − m_effect = REG_COLOR_EFFECT_ON; | |
| 343 | − cfix_r = REG_CFIXR_SEPIA; | |
| 344 | − cfix_b = REG_CFIXB_SEPIA; | |
| 345 | − break; | |
| 346 | − } | |
| 347 | − | |
| 348 | − ret = m5mols_write(sd, PARM_EFFECT, p_effect); | |
| 349 | − if (!ret) | |
| 350 | − ret = m5mols_write(sd, MON_EFFECT, m_effect); | |
| 351 | − | |
| 352 | − if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) { | |
| 353 | − ret = m5mols_write(sd, MON_CFIXR, cfix_r); | |
| 354 | − if (!ret) | |
| 355 | − ret = m5mols_write(sd, MON_CFIXB, cfix_b); | |
| 356 | − } | |
| 357 | − | |
| 358 | − v4l2_dbg(1, m5mols_debug, sd, | |
| 359 | − "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n", | |
| 360 | − p_effect, m_effect, cfix_r, cfix_b, ret); | |
| 361 | − | |
| 362 | − return ret; | |
| 363 | −} | |
| 364 | − | |
| 365 | −static int m5mols_set_iso(struct m5mols_info *info, int auto_iso) | |
| 366 | −{ | |
| 367 | − u32 iso = auto_iso ? 0 : info->iso->val + 1; | |
| 368 | − | |
| 369 | − return m5mols_write(&info->sd, AE_ISO, iso); | |
| 370 | −} | |
| 371 | − | |
| 372 | −static int m5mols_set_wdr(struct m5mols_info *info, int wdr) | |
| 373 | −{ | |
| 374 | − int ret; | |
| 375 | − | |
| 376 | − ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5); | |
| 377 | − if (ret < 0) | |
| 378 | − return ret; | |
| 379 | − | |
| 380 | − ret = m5mols_set_mode(info, REG_CAPTURE); | |
| 381 | − if (ret < 0) | |
| 382 | − return ret; | |
| 383 | − | |
| 384 | − return m5mols_write(&info->sd, CAPP_WDR_EN, wdr); | |
| 385 | −} | |
| 386 | − | |
| 387 | −static int m5mols_set_stabilization(struct m5mols_info *info, int val) | |
| 388 | −{ | |
| 389 | − struct v4l2_subdev *sd = &info->sd; | |
| 390 | − unsigned int evp = val ? 0xe : 0x0; | |
| 391 | − int ret; | |
| 392 | − | |
| 393 | − ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp); | |
| 394 | − if (ret < 0) | |
| 395 | − return ret; | |
| 396 | − | |
| 397 | − return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp); | |
| 398 | −} | |
| 399 | − | |
| 400 | −static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |
| 401 | −{ | |
| 402 | − struct v4l2_subdev *sd = to_sd(ctrl); | |
| 403 | − struct m5mols_info *info = to_m5mols(sd); | |
| 404 | − int ret = 0; | |
| 405 | − u8 status = REG_ISO_AUTO; | |
| 406 | − | |
| 407 | − v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n", | |
| 408 | − __func__, ctrl->name, info->isp_ready); | |
| 409 | − | |
| 410 | − if (!info->isp_ready) | |
| 411 | − return -EBUSY; | |
| 412 | − | |
| 413 | − switch (ctrl->id) { | |
| 414 | − case V4L2_CID_ISO_SENSITIVITY_AUTO: | |
| 415 | − ret = m5mols_read_u8(sd, AE_ISO, &status); | |
| 416 | − if (ret == 0) | |
| 417 | − ctrl->val = !status; | |
| 418 | − if (status != REG_ISO_AUTO) | |
| 419 | − info->iso->val = status - 1; | |
| 420 | − break; | |
| 421 | − | |
| 422 | − case V4L2_CID_3A_LOCK: | |
| 423 | − ctrl->val &= ~0x7; | |
| 424 | − | |
| 425 | − ret = m5mols_read_u8(sd, AE_LOCK, &status); | |
| 426 | − if (ret) | |
| 427 | − return ret; | |
| 428 | − if (status) | |
| 429 | − info->lock_3a->val |= V4L2_LOCK_EXPOSURE; | |
| 430 | − | |
| 431 | − ret = m5mols_read_u8(sd, AWB_LOCK, &status); | |
| 432 | − if (ret) | |
| 433 | − return ret; | |
| 434 | − if (status) | |
| 435 | − info->lock_3a->val |= V4L2_LOCK_EXPOSURE; | |
| 436 | − | |
| 437 | − ret = m5mols_read_u8(sd, AF_EXECUTE, &status); | |
| 438 | − if (!status) | |
| 439 | − info->lock_3a->val |= V4L2_LOCK_EXPOSURE; | |
| 440 | − break; | |
| 441 | − } | |
| 442 | − | |
| 443 | − return ret; | |
| 444 | −} | |
| 445 | − | |
| 446 | −static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 447 | −{ | |
| 448 | − unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl); | |
| 449 | − struct v4l2_subdev *sd = to_sd(ctrl); | |
| 450 | − struct m5mols_info *info = to_m5mols(sd); | |
| 451 | − int last_mode = info->mode; | |
| 452 | − int ret = 0; | |
| 453 | − | |
| 454 | − /* | |
| 455 | − * If needed, defer restoring the controls until | |
| 456 | − * the device is fully initialized. | |
| 457 | − */ | |
| 458 | − if (!info->isp_ready) { | |
| 459 | − info->ctrl_sync = 0; | |
| 460 | − return 0; | |
| 461 | − } | |
| 462 | − | |
| 463 | − v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %p\n", | |
| 464 | − __func__, ctrl->name, ctrl->val, ctrl->priv); | |
| 465 | − | |
| 466 | − if (ctrl_mode && ctrl_mode != info->mode) { | |
| 467 | − ret = m5mols_set_mode(info, ctrl_mode); | |
| 468 | − if (ret < 0) | |
| 469 | − return ret; | |
| 470 | − } | |
| 471 | − | |
| 472 | − switch (ctrl->id) { | |
| 473 | − case V4L2_CID_3A_LOCK: | |
| 474 | − ret = m5mols_3a_lock(info, ctrl); | |
| 475 | − break; | |
| 476 | − | |
| 477 | − case V4L2_CID_ZOOM_ABSOLUTE: | |
| 478 | − ret = m5mols_write(sd, MON_ZOOM, ctrl->val); | |
| 479 | − break; | |
| 480 | − | |
| 481 | − case V4L2_CID_EXPOSURE_AUTO: | |
| 482 | − ret = m5mols_set_exposure(info, ctrl->val); | |
| 483 | − break; | |
| 484 | − | |
| 485 | − case V4L2_CID_ISO_SENSITIVITY: | |
| 486 | − ret = m5mols_set_iso(info, ctrl->val); | |
| 487 | − break; | |
| 488 | − | |
| 489 | − case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: | |
| 490 | − ret = m5mols_set_white_balance(info, ctrl->val); | |
| 491 | − break; | |
| 492 | − | |
| 493 | − case V4L2_CID_SATURATION: | |
| 494 | − ret = m5mols_set_saturation(info, ctrl->val); | |
| 495 | − break; | |
| 496 | − | |
| 497 | − case V4L2_CID_COLORFX: | |
| 498 | − ret = m5mols_set_color_effect(info, ctrl->val); | |
| 499 | − break; | |
| 500 | − | |
| 501 | − case V4L2_CID_WIDE_DYNAMIC_RANGE: | |
| 502 | − ret = m5mols_set_wdr(info, ctrl->val); | |
| 503 | − break; | |
| 504 | − | |
| 505 | − case V4L2_CID_IMAGE_STABILIZATION: | |
| 506 | − ret = m5mols_set_stabilization(info, ctrl->val); | |
| 507 | − break; | |
| 508 | − | |
| 509 | − case V4L2_CID_JPEG_COMPRESSION_QUALITY: | |
| 510 | − ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val); | |
| 511 | − break; | |
| 512 | − } | |
| 513 | − | |
| 514 | − if (ret == 0 && info->mode != last_mode) | |
| 515 | − ret = m5mols_set_mode(info, last_mode); | |
| 516 | − | |
| 517 | − return ret; | |
| 518 | −} | |
| 519 | − | |
| 520 | −static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { | |
| 521 | − .g_volatile_ctrl = m5mols_g_volatile_ctrl, | |
| 522 | − .s_ctrl = m5mols_s_ctrl, | |
| 523 | −}; | |
| 524 | − | |
| 525 | −/* Supported manual ISO values */ | |
| 526 | −static const s64 iso_qmenu[] = { | |
| 527 | − /* AE_ISO: 0x01...0x07 (ISO: 50...3200) */ | |
| 528 | − 50000, 100000, 200000, 400000, 800000, 1600000, 3200000 | |
| 529 | −}; | |
| 530 | − | |
| 531 | −/* Supported Exposure Bias values, -2.0EV...+2.0EV */ | |
| 532 | −static const s64 ev_bias_qmenu[] = { | |
| 533 | − /* AE_INDEX: 0x00...0x08 */ | |
| 534 | − -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000 | |
| 535 | −}; | |
| 536 | − | |
| 537 | −int m5mols_init_controls(struct v4l2_subdev *sd) | |
| 538 | −{ | |
| 539 | − struct m5mols_info *info = to_m5mols(sd); | |
| 540 | − u16 exposure_max; | |
| 541 | − u16 zoom_step; | |
| 542 | − int ret; | |
| 543 | − | |
| 544 | − /* Determine the firmware dependent control range and step values */ | |
| 545 | − ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max); | |
| 546 | − if (ret < 0) | |
| 547 | − return ret; | |
| 548 | − | |
| 549 | − zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; | |
| 550 | − v4l2_ctrl_handler_init(&info->handle, 20); | |
| 551 | − | |
| 552 | − info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle, | |
| 553 | − &m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, | |
| 554 | − 9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO); | |
| 555 | − | |
| 556 | − /* Exposure control cluster */ | |
| 557 | − info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle, | |
| 558 | − &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | |
| 559 | − 1, ~0x03, V4L2_EXPOSURE_AUTO); | |
| 560 | − | |
| 561 | − info->exposure = v4l2_ctrl_new_std(&info->handle, | |
| 562 | − &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, | |
| 563 | − 0, exposure_max, 1, exposure_max / 2); | |
| 564 | − | |
| 565 | − info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle, | |
| 566 | − &m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS, | |
| 567 | − ARRAY_SIZE(ev_bias_qmenu) - 1, | |
| 568 | − ARRAY_SIZE(ev_bias_qmenu)/2 - 1, | |
| 569 | − ev_bias_qmenu); | |
| 570 | − | |
| 571 | − info->metering = v4l2_ctrl_new_std_menu(&info->handle, | |
| 572 | − &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING, | |
| 573 | − 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE); | |
| 574 | − | |
| 575 | − /* ISO control cluster */ | |
| 576 | − info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, | |
| 577 | − V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1); | |
| 578 | − | |
| 579 | − info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops, | |
| 580 | − V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, | |
| 581 | − ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); | |
| 582 | − | |
| 583 | − info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | |
| 584 | − V4L2_CID_SATURATION, 1, 5, 1, 3); | |
| 585 | − | |
| 586 | − info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | |
| 587 | − V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1); | |
| 588 | − | |
| 589 | − info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, | |
| 590 | − V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE); | |
| 591 | − | |
| 592 | − info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | |
| 593 | − V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); | |
| 594 | − | |
| 595 | − info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | |
| 596 | − V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0); | |
| 597 | − | |
| 598 | − info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | |
| 599 | − V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80); | |
| 600 | − | |
| 601 | − info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | |
| 602 | − V4L2_CID_3A_LOCK, 0, 0x7, 0, 0); | |
| 603 | − | |
| 604 | − if (info->handle.error) { | |
| 605 | − int ret = info->handle.error; | |
| 606 | − v4l2_err(sd, "Failed to initialize controls: %d\n", ret); | |
| 607 | − v4l2_ctrl_handler_free(&info->handle); | |
| 608 | − return ret; | |
| 609 | − } | |
| 610 | − | |
| 611 | − v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false); | |
| 612 | − info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE | | |
| 613 | − V4L2_CTRL_FLAG_UPDATE; | |
| 614 | − v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false); | |
| 615 | − | |
| 616 | − info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE; | |
| 617 | − | |
| 618 | − m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER); | |
| 619 | − m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER); | |
| 620 | − m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR); | |
| 621 | − | |
| 622 | − sd->ctrl_handler = &info->handle; | |
| 623 | − | |
| 624 | − return 0; | |
| 625 | −} | |
| @@ -1,1051 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * Driver for M-5MOLS 8M Pixel camera sensor with ISP | |
| 4 | − * | |
| 5 | − * Copyright (C) 2011 Samsung Electronics Co., Ltd. | |
| 6 | − * Author: HeungJun Kim <riverful.kim@samsung.com> | |
| 7 | − * | |
| 8 | − * Copyright (C) 2009 Samsung Electronics Co., Ltd. | |
| 9 | − * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#include <linux/i2c.h> | |
| 13 | −#include <linux/slab.h> | |
| 14 | −#include <linux/irq.h> | |
| 15 | −#include <linux/interrupt.h> | |
| 16 | −#include <linux/delay.h> | |
| 17 | −#include <linux/gpio/consumer.h> | |
| 18 | −#include <linux/regulator/consumer.h> | |
| 19 | −#include <linux/videodev2.h> | |
| 20 | −#include <linux/module.h> | |
| 21 | −#include <media/v4l2-ctrls.h> | |
| 22 | −#include <media/v4l2-device.h> | |
| 23 | −#include <media/v4l2-subdev.h> | |
| 24 | −#include <media/i2c/m5mols.h> | |
| 25 | − | |
| 26 | −#include "m5mols.h" | |
| 27 | −#include "m5mols_reg.h" | |
| 28 | − | |
| 29 | −int m5mols_debug; | |
| 30 | −module_param(m5mols_debug, int, 0644); | |
| 31 | − | |
| 32 | −#define MODULE_NAME "M5MOLS" | |
| 33 | −#define M5MOLS_I2C_CHECK_RETRY 500 | |
| 34 | − | |
| 35 | −/* The regulator consumer names for external voltage regulators */ | |
| 36 | −static struct regulator_bulk_data supplies[] = { | |
| 37 | − { | |
| 38 | − .supply = "core", /* ARM core power, 1.2V */ | |
| 39 | − }, { | |
| 40 | − .supply = "dig_18", /* digital power 1, 1.8V */ | |
| 41 | − }, { | |
| 42 | − .supply = "d_sensor", /* sensor power 1, 1.8V */ | |
| 43 | − }, { | |
| 44 | − .supply = "dig_28", /* digital power 2, 2.8V */ | |
| 45 | − }, { | |
| 46 | − .supply = "a_sensor", /* analog power */ | |
| 47 | − }, { | |
| 48 | − .supply = "dig_12", /* digital power 3, 1.2V */ | |
| 49 | − }, | |
| 50 | −}; | |
| 51 | − | |
| 52 | −static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { | |
| 53 | − [M5MOLS_RESTYPE_MONITOR] = { | |
| 54 | − .width = 1920, | |
| 55 | − .height = 1080, | |
| 56 | − .code = MEDIA_BUS_FMT_VYUY8_2X8, | |
| 57 | − .field = V4L2_FIELD_NONE, | |
| 58 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 59 | − }, | |
| 60 | − [M5MOLS_RESTYPE_CAPTURE] = { | |
| 61 | − .width = 1920, | |
| 62 | − .height = 1080, | |
| 63 | − .code = MEDIA_BUS_FMT_JPEG_1X8, | |
| 64 | − .field = V4L2_FIELD_NONE, | |
| 65 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 66 | − }, | |
| 67 | −}; | |
| 68 | −#define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) | |
| 69 | − | |
| 70 | −static const struct m5mols_resolution m5mols_reg_res[] = { | |
| 71 | − { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ | |
| 72 | − { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ | |
| 73 | − { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ | |
| 74 | − { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, | |
| 75 | − { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ | |
| 76 | − { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ | |
| 77 | − { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ | |
| 78 | − { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ | |
| 79 | − { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ | |
| 80 | − { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, | |
| 81 | − { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ | |
| 82 | − { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ | |
| 83 | − { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, | |
| 84 | − { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ | |
| 85 | − { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ | |
| 86 | − { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ | |
| 87 | − { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ | |
| 88 | − { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ | |
| 89 | − { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ | |
| 90 | − | |
| 91 | − { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ | |
| 92 | − { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ | |
| 93 | − { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, | |
| 94 | − { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ | |
| 95 | − { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ | |
| 96 | − { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ | |
| 97 | − { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ | |
| 98 | − { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ | |
| 99 | − { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ | |
| 100 | − { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ | |
| 101 | − { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ | |
| 102 | − { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, | |
| 103 | − { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ | |
| 104 | − { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, | |
| 105 | − { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ | |
| 106 | − { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ | |
| 107 | − { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, | |
| 108 | − { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ | |
| 109 | −}; | |
| 110 | − | |
| 111 | −/** | |
| 112 | − * m5mols_swap_byte - an byte array to integer conversion function | |
| 113 | − * @data: byte array | |
| 114 | − * @length: size in bytes of I2C packet defined in the M-5MOLS datasheet | |
| 115 | − * | |
| 116 | − * Convert I2C data byte array with performing any required byte | |
| 117 | − * reordering to assure proper values for each data type, regardless | |
| 118 | − * of the architecture endianness. | |
| 119 | − */ | |
| 120 | −static u32 m5mols_swap_byte(u8 *data, u8 length) | |
| 121 | −{ | |
| 122 | − if (length == 1) | |
| 123 | − return *data; | |
| 124 | − else if (length == 2) | |
| 125 | − return be16_to_cpu(*((__be16 *)data)); | |
| 126 | − else | |
| 127 | − return be32_to_cpu(*((__be32 *)data)); | |
| 128 | −} | |
| 129 | − | |
| 130 | −/** | |
| 131 | − * m5mols_read - I2C read function | |
| 132 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 133 | − * @size: desired size of I2C packet | |
| 134 | − * @reg: combination of size, category and command for the I2C packet | |
| 135 | − * @val: read value | |
| 136 | − * | |
| 137 | − * Returns 0 on success, or else negative errno. | |
| 138 | − */ | |
| 139 | −static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) | |
| 140 | −{ | |
| 141 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 142 | − struct m5mols_info *info = to_m5mols(sd); | |
| 143 | − u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; | |
| 144 | − u8 category = I2C_CATEGORY(reg); | |
| 145 | − u8 cmd = I2C_COMMAND(reg); | |
| 146 | − struct i2c_msg msg[2]; | |
| 147 | − u8 wbuf[5]; | |
| 148 | − int ret; | |
| 149 | − | |
| 150 | − if (!client->adapter) | |
| 151 | − return -ENODEV; | |
| 152 | − | |
| 153 | − msg[0].addr = client->addr; | |
| 154 | − msg[0].flags = 0; | |
| 155 | − msg[0].len = 5; | |
| 156 | − msg[0].buf = wbuf; | |
| 157 | − wbuf[0] = 5; | |
| 158 | − wbuf[1] = M5MOLS_BYTE_READ; | |
| 159 | − wbuf[2] = category; | |
| 160 | − wbuf[3] = cmd; | |
| 161 | − wbuf[4] = size; | |
| 162 | − | |
| 163 | − msg[1].addr = client->addr; | |
| 164 | − msg[1].flags = I2C_M_RD; | |
| 165 | − msg[1].len = size + 1; | |
| 166 | − msg[1].buf = rbuf; | |
| 167 | − | |
| 168 | − /* minimum stabilization time */ | |
| 169 | − usleep_range(200, 300); | |
| 170 | − | |
| 171 | − ret = i2c_transfer(client->adapter, msg, 2); | |
| 172 | − | |
| 173 | − if (ret == 2) { | |
| 174 | − *val = m5mols_swap_byte(&rbuf[1], size); | |
| 175 | − return 0; | |
| 176 | − } | |
| 177 | − | |
| 178 | − if (info->isp_ready) | |
| 179 | − v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", | |
| 180 | − size, category, cmd, ret); | |
| 181 | − | |
| 182 | − return ret < 0 ? ret : -EIO; | |
| 183 | −} | |
| 184 | − | |
| 185 | −int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) | |
| 186 | −{ | |
| 187 | − u32 val_32; | |
| 188 | − int ret; | |
| 189 | − | |
| 190 | − if (I2C_SIZE(reg) != 1) { | |
| 191 | − v4l2_err(sd, "Wrong data size\n"); | |
| 192 | − return -EINVAL; | |
| 193 | − } | |
| 194 | − | |
| 195 | − ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); | |
| 196 | − if (ret) | |
| 197 | − return ret; | |
| 198 | − | |
| 199 | − *val = (u8)val_32; | |
| 200 | − return ret; | |
| 201 | −} | |
| 202 | − | |
| 203 | −int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val) | |
| 204 | −{ | |
| 205 | − u32 val_32; | |
| 206 | − int ret; | |
| 207 | − | |
| 208 | − if (I2C_SIZE(reg) != 2) { | |
| 209 | − v4l2_err(sd, "Wrong data size\n"); | |
| 210 | − return -EINVAL; | |
| 211 | − } | |
| 212 | − | |
| 213 | − ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); | |
| 214 | − if (ret) | |
| 215 | − return ret; | |
| 216 | − | |
| 217 | − *val = (u16)val_32; | |
| 218 | − return ret; | |
| 219 | −} | |
| 220 | − | |
| 221 | −int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) | |
| 222 | −{ | |
| 223 | − if (I2C_SIZE(reg) != 4) { | |
| 224 | − v4l2_err(sd, "Wrong data size\n"); | |
| 225 | − return -EINVAL; | |
| 226 | − } | |
| 227 | − | |
| 228 | − return m5mols_read(sd, I2C_SIZE(reg), reg, val); | |
| 229 | −} | |
| 230 | − | |
| 231 | −/** | |
| 232 | − * m5mols_write - I2C command write function | |
| 233 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 234 | − * @reg: combination of size, category and command for the I2C packet | |
| 235 | − * @val: value to write | |
| 236 | − * | |
| 237 | − * Returns 0 on success, or else negative errno. | |
| 238 | − */ | |
| 239 | −int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) | |
| 240 | −{ | |
| 241 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 242 | − struct m5mols_info *info = to_m5mols(sd); | |
| 243 | − u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; | |
| 244 | − u8 category = I2C_CATEGORY(reg); | |
| 245 | − u8 cmd = I2C_COMMAND(reg); | |
| 246 | − u8 size = I2C_SIZE(reg); | |
| 247 | − u32 *buf = (u32 *)&wbuf[4]; | |
| 248 | − struct i2c_msg msg[1]; | |
| 249 | − int ret; | |
| 250 | − | |
| 251 | − if (!client->adapter) | |
| 252 | − return -ENODEV; | |
| 253 | − | |
| 254 | − if (size != 1 && size != 2 && size != 4) { | |
| 255 | − v4l2_err(sd, "Wrong data size\n"); | |
| 256 | − return -EINVAL; | |
| 257 | − } | |
| 258 | − | |
| 259 | − msg->addr = client->addr; | |
| 260 | − msg->flags = 0; | |
| 261 | − msg->len = (u16)size + 4; | |
| 262 | − msg->buf = wbuf; | |
| 263 | − wbuf[0] = size + 4; | |
| 264 | − wbuf[1] = M5MOLS_BYTE_WRITE; | |
| 265 | − wbuf[2] = category; | |
| 266 | − wbuf[3] = cmd; | |
| 267 | − | |
| 268 | − *buf = m5mols_swap_byte((u8 *)&val, size); | |
| 269 | − | |
| 270 | − /* minimum stabilization time */ | |
| 271 | − usleep_range(200, 300); | |
| 272 | − | |
| 273 | − ret = i2c_transfer(client->adapter, msg, 1); | |
| 274 | − if (ret == 1) | |
| 275 | − return 0; | |
| 276 | − | |
| 277 | − if (info->isp_ready) | |
| 278 | − v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n", | |
| 279 | − category, cmd, ret); | |
| 280 | − | |
| 281 | − return ret < 0 ? ret : -EIO; | |
| 282 | −} | |
| 283 | − | |
| 284 | −/** | |
| 285 | − * m5mols_busy_wait - Busy waiting with I2C register polling | |
| 286 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 287 | − * @reg: the I2C_REG() address of an 8-bit status register to check | |
| 288 | − * @value: expected status register value | |
| 289 | − * @mask: bit mask for the read status register value | |
| 290 | − * @timeout: timeout in milliseconds, or -1 for default timeout | |
| 291 | − * | |
| 292 | − * The @reg register value is ORed with @mask before comparing with @value. | |
| 293 | − * | |
| 294 | − * Return: 0 if the requested condition became true within less than | |
| 295 | − * @timeout ms, or else negative errno. | |
| 296 | − */ | |
| 297 | −int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, | |
| 298 | − int timeout) | |
| 299 | −{ | |
| 300 | − int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout; | |
| 301 | − unsigned long end = jiffies + msecs_to_jiffies(ms); | |
| 302 | − u8 status; | |
| 303 | − | |
| 304 | − do { | |
| 305 | − int ret = m5mols_read_u8(sd, reg, &status); | |
| 306 | − | |
| 307 | − if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL)) | |
| 308 | − return ret; | |
| 309 | − if (!ret && (status & mask & 0xff) == (value & 0xff)) | |
| 310 | − return 0; | |
| 311 | − usleep_range(100, 250); | |
| 312 | − } while (ms > 0 && time_is_after_jiffies(end)); | |
| 313 | − | |
| 314 | − return -EBUSY; | |
| 315 | −} | |
| 316 | − | |
| 317 | −/** | |
| 318 | − * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts | |
| 319 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 320 | − * @reg: combination of size, category and command for the I2C packet | |
| 321 | − * | |
| 322 | − * Before writing desired interrupt value the INT_FACTOR register should | |
| 323 | − * be read to clear pending interrupts. | |
| 324 | − */ | |
| 325 | −int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) | |
| 326 | −{ | |
| 327 | − struct m5mols_info *info = to_m5mols(sd); | |
| 328 | − u8 mask = is_available_af(info) ? REG_INT_AF : 0; | |
| 329 | − u8 dummy; | |
| 330 | − int ret; | |
| 331 | − | |
| 332 | − ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy); | |
| 333 | − if (!ret) | |
| 334 | − ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); | |
| 335 | − return ret; | |
| 336 | −} | |
| 337 | − | |
| 338 | −int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout) | |
| 339 | −{ | |
| 340 | − struct m5mols_info *info = to_m5mols(sd); | |
| 341 | − | |
| 342 | − int ret = wait_event_interruptible_timeout(info->irq_waitq, | |
| 343 | − atomic_add_unless(&info->irq_done, -1, 0), | |
| 344 | − msecs_to_jiffies(timeout)); | |
| 345 | − if (ret <= 0) | |
| 346 | − return ret ? ret : -ETIMEDOUT; | |
| 347 | − | |
| 348 | − return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask, | |
| 349 | − M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1); | |
| 350 | −} | |
| 351 | − | |
| 352 | −/** | |
| 353 | − * m5mols_reg_mode - Write the mode and check busy status | |
| 354 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 355 | − * @mode: the required operation mode | |
| 356 | − * | |
| 357 | − * It always accompanies a little delay changing the M-5MOLS mode, so it is | |
| 358 | − * needed checking current busy status to guarantee right mode. | |
| 359 | − */ | |
| 360 | −static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) | |
| 361 | −{ | |
| 362 | − int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); | |
| 363 | − if (ret < 0) | |
| 364 | − return ret; | |
| 365 | − return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff, | |
| 366 | − M5MOLS_MODE_CHANGE_TIMEOUT); | |
| 367 | −} | |
| 368 | − | |
| 369 | −/** | |
| 370 | − * m5mols_set_mode - set the M-5MOLS controller mode | |
| 371 | − * @info: M-5MOLS driver data structure | |
| 372 | − * @mode: the required operation mode | |
| 373 | − * | |
| 374 | − * The commands of M-5MOLS are grouped into specific modes. Each functionality | |
| 375 | − * can be guaranteed only when the sensor is operating in mode which a command | |
| 376 | − * belongs to. | |
| 377 | − */ | |
| 378 | −int m5mols_set_mode(struct m5mols_info *info, u8 mode) | |
| 379 | −{ | |
| 380 | − struct v4l2_subdev *sd = &info->sd; | |
| 381 | − int ret = -EINVAL; | |
| 382 | − u8 reg; | |
| 383 | − | |
| 384 | − if (mode < REG_PARAMETER || mode > REG_CAPTURE) | |
| 385 | − return ret; | |
| 386 | − | |
| 387 | − ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); | |
| 388 | − if (ret || reg == mode) | |
| 389 | − return ret; | |
| 390 | − | |
| 391 | − switch (reg) { | |
| 392 | − case REG_PARAMETER: | |
| 393 | − ret = m5mols_reg_mode(sd, REG_MONITOR); | |
| 394 | − if (mode == REG_MONITOR) | |
| 395 | − break; | |
| 396 | − if (!ret) | |
| 397 | − ret = m5mols_reg_mode(sd, REG_CAPTURE); | |
| 398 | − break; | |
| 399 | − | |
| 400 | − case REG_MONITOR: | |
| 401 | − if (mode == REG_PARAMETER) { | |
| 402 | − ret = m5mols_reg_mode(sd, REG_PARAMETER); | |
| 403 | − break; | |
| 404 | − } | |
| 405 | − | |
| 406 | − ret = m5mols_reg_mode(sd, REG_CAPTURE); | |
| 407 | − break; | |
| 408 | − | |
| 409 | − case REG_CAPTURE: | |
| 410 | − ret = m5mols_reg_mode(sd, REG_MONITOR); | |
| 411 | − if (mode == REG_MONITOR) | |
| 412 | − break; | |
| 413 | − if (!ret) | |
| 414 | − ret = m5mols_reg_mode(sd, REG_PARAMETER); | |
| 415 | − break; | |
| 416 | − | |
| 417 | − default: | |
| 418 | − v4l2_warn(sd, "Wrong mode: %d\n", mode); | |
| 419 | − } | |
| 420 | − | |
| 421 | − if (!ret) | |
| 422 | − info->mode = mode; | |
| 423 | − | |
| 424 | − return ret; | |
| 425 | −} | |
| 426 | − | |
| 427 | −/** | |
| 428 | − * m5mols_get_version - retrieve full revisions information of M-5MOLS | |
| 429 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 430 | − * | |
| 431 | − * The version information includes revisions of hardware and firmware, | |
| 432 | − * AutoFocus alghorithm version and the version string. | |
| 433 | − */ | |
| 434 | −static int m5mols_get_version(struct v4l2_subdev *sd) | |
| 435 | −{ | |
| 436 | − struct m5mols_info *info = to_m5mols(sd); | |
| 437 | − struct m5mols_version *ver = &info->ver; | |
| 438 | − u8 *str = ver->str; | |
| 439 | − int i; | |
| 440 | − int ret; | |
| 441 | − | |
| 442 | − ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer); | |
| 443 | − if (!ret) | |
| 444 | − ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project); | |
| 445 | − if (!ret) | |
| 446 | − ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw); | |
| 447 | − if (!ret) | |
| 448 | − ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw); | |
| 449 | − if (!ret) | |
| 450 | − ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param); | |
| 451 | − if (!ret) | |
| 452 | − ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb); | |
| 453 | − if (!ret) | |
| 454 | − ret = m5mols_read_u8(sd, AF_VERSION, &ver->af); | |
| 455 | − if (ret) | |
| 456 | − return ret; | |
| 457 | − | |
| 458 | − for (i = 0; i < VERSION_STRING_SIZE; i++) { | |
| 459 | − ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]); | |
| 460 | − if (ret) | |
| 461 | − return ret; | |
| 462 | − } | |
| 463 | − | |
| 464 | − v4l2_info(sd, "Manufacturer\t[%s]\n", | |
| 465 | − is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? | |
| 466 | − "Samsung Electro-Mechanics" : | |
| 467 | − is_manufacturer(info, REG_SAMSUNG_OPTICS) ? | |
| 468 | − "Samsung Fiber-Optics" : | |
| 469 | − is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? | |
| 470 | − "Samsung Techwin" : "None"); | |
| 471 | − v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", | |
| 472 | − info->ver.customer, info->ver.project); | |
| 473 | − | |
| 474 | − if (!is_available_af(info)) | |
| 475 | − v4l2_info(sd, "No support Auto Focus on this firmware\n"); | |
| 476 | − | |
| 477 | − return ret; | |
| 478 | −} | |
| 479 | − | |
| 480 | −/** | |
| 481 | − * __find_restype - Lookup M-5MOLS resolution type according to pixel code | |
| 482 | − * @code: pixel code | |
| 483 | − */ | |
| 484 | −static enum m5mols_restype __find_restype(u32 code) | |
| 485 | −{ | |
| 486 | − enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; | |
| 487 | − | |
| 488 | − do { | |
| 489 | − if (code == m5mols_default_ffmt[type].code) | |
| 490 | − return type; | |
| 491 | − } while (++type != SIZE_DEFAULT_FFMT); | |
| 492 | − | |
| 493 | − return 0; | |
| 494 | −} | |
| 495 | − | |
| 496 | −/** | |
| 497 | − * __find_resolution - Lookup preset and type of M-5MOLS's resolution | |
| 498 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 499 | − * @mf: pixel format to find/negotiate the resolution preset for | |
| 500 | − * @type: M-5MOLS resolution type | |
| 501 | − * @resolution: M-5MOLS resolution preset register value | |
| 502 | − * | |
| 503 | − * Find nearest resolution matching resolution preset and adjust mf | |
| 504 | − * to supported values. | |
| 505 | − */ | |
| 506 | −static int __find_resolution(struct v4l2_subdev *sd, | |
| 507 | − struct v4l2_mbus_framefmt *mf, | |
| 508 | − enum m5mols_restype *type, | |
| 509 | − u32 *resolution) | |
| 510 | −{ | |
| 511 | − const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; | |
| 512 | − const struct m5mols_resolution *match = NULL; | |
| 513 | − enum m5mols_restype stype = __find_restype(mf->code); | |
| 514 | − int i = ARRAY_SIZE(m5mols_reg_res); | |
| 515 | − unsigned int min_err = ~0; | |
| 516 | − | |
| 517 | − while (i--) { | |
| 518 | − int err; | |
| 519 | − if (stype == fsize->type) { | |
| 520 | − err = abs(fsize->width - mf->width) | |
| 521 | − + abs(fsize->height - mf->height); | |
| 522 | − | |
| 523 | − if (err < min_err) { | |
| 524 | − min_err = err; | |
| 525 | − match = fsize; | |
| 526 | − } | |
| 527 | − } | |
| 528 | − fsize++; | |
| 529 | − } | |
| 530 | − if (match) { | |
| 531 | − mf->width = match->width; | |
| 532 | − mf->height = match->height; | |
| 533 | − *resolution = match->reg; | |
| 534 | − *type = stype; | |
| 535 | − return 0; | |
| 536 | − } | |
| 537 | − | |
| 538 | − return -EINVAL; | |
| 539 | −} | |
| 540 | − | |
| 541 | −static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, | |
| 542 | − struct v4l2_subdev_state *sd_state, | |
| 543 | − enum v4l2_subdev_format_whence which, | |
| 544 | − enum m5mols_restype type) | |
| 545 | −{ | |
| 546 | − if (which == V4L2_SUBDEV_FORMAT_TRY) | |
| 547 | − return sd_state ? v4l2_subdev_get_try_format(&info->sd, | |
| 548 | − sd_state, 0) : NULL; | |
| 549 | − | |
| 550 | − return &info->ffmt[type]; | |
| 551 | −} | |
| 552 | − | |
| 553 | −static int m5mols_get_fmt(struct v4l2_subdev *sd, | |
| 554 | − struct v4l2_subdev_state *sd_state, | |
| 555 | − struct v4l2_subdev_format *fmt) | |
| 556 | −{ | |
| 557 | − struct m5mols_info *info = to_m5mols(sd); | |
| 558 | − struct v4l2_mbus_framefmt *format; | |
| 559 | − int ret = 0; | |
| 560 | − | |
| 561 | − mutex_lock(&info->lock); | |
| 562 | − | |
| 563 | − format = __find_format(info, sd_state, fmt->which, info->res_type); | |
| 564 | − if (format) | |
| 565 | − fmt->format = *format; | |
| 566 | − else | |
| 567 | − ret = -EINVAL; | |
| 568 | − | |
| 569 | − mutex_unlock(&info->lock); | |
| 570 | − return ret; | |
| 571 | −} | |
| 572 | − | |
| 573 | −static int m5mols_set_fmt(struct v4l2_subdev *sd, | |
| 574 | − struct v4l2_subdev_state *sd_state, | |
| 575 | − struct v4l2_subdev_format *fmt) | |
| 576 | −{ | |
| 577 | − struct m5mols_info *info = to_m5mols(sd); | |
| 578 | − struct v4l2_mbus_framefmt *format = &fmt->format; | |
| 579 | − struct v4l2_mbus_framefmt *sfmt; | |
| 580 | − enum m5mols_restype type; | |
| 581 | − u32 resolution = 0; | |
| 582 | − int ret; | |
| 583 | − | |
| 584 | − ret = __find_resolution(sd, format, &type, &resolution); | |
| 585 | − if (ret < 0) | |
| 586 | − return ret; | |
| 587 | − | |
| 588 | − sfmt = __find_format(info, sd_state, fmt->which, type); | |
| 589 | − if (!sfmt) | |
| 590 | − return 0; | |
| 591 | − | |
| 592 | − mutex_lock(&info->lock); | |
| 593 | − | |
| 594 | − format->code = m5mols_default_ffmt[type].code; | |
| 595 | − format->colorspace = V4L2_COLORSPACE_JPEG; | |
| 596 | − format->field = V4L2_FIELD_NONE; | |
| 597 | − | |
| 598 | − if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | |
| 599 | − *sfmt = *format; | |
| 600 | − info->resolution = resolution; | |
| 601 | − info->res_type = type; | |
| 602 | − } | |
| 603 | − | |
| 604 | − mutex_unlock(&info->lock); | |
| 605 | − return ret; | |
| 606 | −} | |
| 607 | − | |
| 608 | −static int m5mols_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, | |
| 609 | − struct v4l2_mbus_frame_desc *fd) | |
| 610 | −{ | |
| 611 | − struct m5mols_info *info = to_m5mols(sd); | |
| 612 | − | |
| 613 | − if (pad != 0 || fd == NULL) | |
| 614 | − return -EINVAL; | |
| 615 | − | |
| 616 | − mutex_lock(&info->lock); | |
| 617 | − /* | |
| 618 | − * .get_frame_desc is only used for compressed formats, | |
| 619 | − * thus we always return the capture frame parameters here. | |
| 620 | − */ | |
| 621 | − fd->entry[0].length = info->cap.buf_size; | |
| 622 | − fd->entry[0].pixelcode = info->ffmt[M5MOLS_RESTYPE_CAPTURE].code; | |
| 623 | − mutex_unlock(&info->lock); | |
| 624 | − | |
| 625 | − fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; | |
| 626 | − fd->num_entries = 1; | |
| 627 | − | |
| 628 | − return 0; | |
| 629 | −} | |
| 630 | − | |
| 631 | −static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, | |
| 632 | − struct v4l2_mbus_frame_desc *fd) | |
| 633 | −{ | |
| 634 | − struct m5mols_info *info = to_m5mols(sd); | |
| 635 | − struct v4l2_mbus_framefmt *mf = &info->ffmt[M5MOLS_RESTYPE_CAPTURE]; | |
| 636 | − | |
| 637 | − if (pad != 0 || fd == NULL) | |
| 638 | − return -EINVAL; | |
| 639 | − | |
| 640 | − fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; | |
| 641 | − fd->num_entries = 1; | |
| 642 | − fd->entry[0].length = clamp_t(u32, fd->entry[0].length, | |
| 643 | − mf->width * mf->height, | |
| 644 | − M5MOLS_MAIN_JPEG_SIZE_MAX); | |
| 645 | − mutex_lock(&info->lock); | |
| 646 | − info->cap.buf_size = fd->entry[0].length; | |
| 647 | − mutex_unlock(&info->lock); | |
| 648 | − | |
| 649 | − return 0; | |
| 650 | −} | |
| 651 | − | |
| 652 | − | |
| 653 | −static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, | |
| 654 | − struct v4l2_subdev_state *sd_state, | |
| 655 | − struct v4l2_subdev_mbus_code_enum *code) | |
| 656 | −{ | |
| 657 | − if (!code || code->index >= SIZE_DEFAULT_FFMT) | |
| 658 | − return -EINVAL; | |
| 659 | − | |
| 660 | − code->code = m5mols_default_ffmt[code->index].code; | |
| 661 | − | |
| 662 | − return 0; | |
| 663 | −} | |
| 664 | − | |
| 665 | −static const struct v4l2_subdev_pad_ops m5mols_pad_ops = { | |
| 666 | − .enum_mbus_code = m5mols_enum_mbus_code, | |
| 667 | − .get_fmt = m5mols_get_fmt, | |
| 668 | − .set_fmt = m5mols_set_fmt, | |
| 669 | − .get_frame_desc = m5mols_get_frame_desc, | |
| 670 | − .set_frame_desc = m5mols_set_frame_desc, | |
| 671 | −}; | |
| 672 | − | |
| 673 | −/** | |
| 674 | − * m5mols_restore_controls - Apply current control values to the registers | |
| 675 | − * @info: M-5MOLS driver data structure | |
| 676 | − * | |
| 677 | − * m5mols_do_scenemode() handles all parameters for which there is yet no | |
| 678 | − * individual control. It should be replaced at some point by setting each | |
| 679 | − * control individually, in required register set up order. | |
| 680 | − */ | |
| 681 | −int m5mols_restore_controls(struct m5mols_info *info) | |
| 682 | −{ | |
| 683 | − int ret; | |
| 684 | − | |
| 685 | − if (info->ctrl_sync) | |
| 686 | − return 0; | |
| 687 | − | |
| 688 | − ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); | |
| 689 | − if (ret) | |
| 690 | − return ret; | |
| 691 | − | |
| 692 | − ret = v4l2_ctrl_handler_setup(&info->handle); | |
| 693 | − info->ctrl_sync = !ret; | |
| 694 | − | |
| 695 | − return ret; | |
| 696 | −} | |
| 697 | − | |
| 698 | −/** | |
| 699 | − * m5mols_start_monitor - Start the monitor mode | |
| 700 | − * @info: M-5MOLS driver data structure | |
| 701 | − * | |
| 702 | − * Before applying the controls setup the resolution and frame rate | |
| 703 | − * in PARAMETER mode, and then switch over to MONITOR mode. | |
| 704 | − */ | |
| 705 | −static int m5mols_start_monitor(struct m5mols_info *info) | |
| 706 | −{ | |
| 707 | − struct v4l2_subdev *sd = &info->sd; | |
| 708 | − int ret; | |
| 709 | − | |
| 710 | − ret = m5mols_set_mode(info, REG_PARAMETER); | |
| 711 | − if (!ret) | |
| 712 | − ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); | |
| 713 | − if (!ret) | |
| 714 | − ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); | |
| 715 | − if (!ret) | |
| 716 | − ret = m5mols_set_mode(info, REG_MONITOR); | |
| 717 | − if (!ret) | |
| 718 | − ret = m5mols_restore_controls(info); | |
| 719 | − | |
| 720 | − return ret; | |
| 721 | −} | |
| 722 | − | |
| 723 | −static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) | |
| 724 | −{ | |
| 725 | − struct m5mols_info *info = to_m5mols(sd); | |
| 726 | − u32 code; | |
| 727 | − int ret; | |
| 728 | − | |
| 729 | − mutex_lock(&info->lock); | |
| 730 | − code = info->ffmt[info->res_type].code; | |
| 731 | − | |
| 732 | − if (enable) { | |
| 733 | − if (is_code(code, M5MOLS_RESTYPE_MONITOR)) | |
| 734 | − ret = m5mols_start_monitor(info); | |
| 735 | − else if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) | |
| 736 | − ret = m5mols_start_capture(info); | |
| 737 | − else | |
| 738 | − ret = -EINVAL; | |
| 739 | − } else { | |
| 740 | − ret = m5mols_set_mode(info, REG_PARAMETER); | |
| 741 | − } | |
| 742 | − | |
| 743 | − mutex_unlock(&info->lock); | |
| 744 | − return ret; | |
| 745 | −} | |
| 746 | − | |
| 747 | −static const struct v4l2_subdev_video_ops m5mols_video_ops = { | |
| 748 | − .s_stream = m5mols_s_stream, | |
| 749 | −}; | |
| 750 | − | |
| 751 | −static int m5mols_sensor_power(struct m5mols_info *info, bool enable) | |
| 752 | −{ | |
| 753 | − struct v4l2_subdev *sd = &info->sd; | |
| 754 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 755 | − int ret; | |
| 756 | − | |
| 757 | − if (info->power == enable) | |
| 758 | − return 0; | |
| 759 | − | |
| 760 | − if (enable) { | |
| 761 | − if (info->set_power) { | |
| 762 | − ret = info->set_power(&client->dev, 1); | |
| 763 | − if (ret) | |
| 764 | − return ret; | |
| 765 | − } | |
| 766 | − | |
| 767 | − ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); | |
| 768 | − if (ret) { | |
| 769 | − if (info->set_power) | |
| 770 | − info->set_power(&client->dev, 0); | |
| 771 | − return ret; | |
| 772 | − } | |
| 773 | − | |
| 774 | − gpiod_set_value(info->reset, 0); | |
| 775 | − info->power = 1; | |
| 776 | − | |
| 777 | − return ret; | |
| 778 | − } | |
| 779 | − | |
| 780 | − ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); | |
| 781 | − if (ret) | |
| 782 | − return ret; | |
| 783 | − | |
| 784 | − if (info->set_power) | |
| 785 | − info->set_power(&client->dev, 0); | |
| 786 | − | |
| 787 | − gpiod_set_value(info->reset, 1); | |
| 788 | − | |
| 789 | − info->isp_ready = 0; | |
| 790 | − info->power = 0; | |
| 791 | − | |
| 792 | − return ret; | |
| 793 | −} | |
| 794 | − | |
| 795 | −/* m5mols_update_fw - optional firmware update routine */ | |
| 796 | −int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, | |
| 797 | − int (*set_power)(struct m5mols_info *, bool)) | |
| 798 | −{ | |
| 799 | − return 0; | |
| 800 | −} | |
| 801 | − | |
| 802 | −/** | |
| 803 | − * m5mols_fw_start - M-5MOLS internal ARM controller initialization | |
| 804 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 805 | − * | |
| 806 | − * Execute the M-5MOLS internal ARM controller initialization sequence. | |
| 807 | − * This function should be called after the supply voltage has been | |
| 808 | − * applied and before any requests to the device are made. | |
| 809 | − */ | |
| 810 | −static int m5mols_fw_start(struct v4l2_subdev *sd) | |
| 811 | −{ | |
| 812 | − struct m5mols_info *info = to_m5mols(sd); | |
| 813 | − int ret; | |
| 814 | − | |
| 815 | − atomic_set(&info->irq_done, 0); | |
| 816 | − /* Wait until I2C slave is initialized in Flash Writer mode */ | |
| 817 | − ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE, | |
| 818 | − M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1); | |
| 819 | − if (!ret) | |
| 820 | − ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); | |
| 821 | − if (!ret) | |
| 822 | − ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000); | |
| 823 | − if (ret < 0) | |
| 824 | − return ret; | |
| 825 | − | |
| 826 | − info->isp_ready = 1; | |
| 827 | − | |
| 828 | − ret = m5mols_get_version(sd); | |
| 829 | − if (!ret) | |
| 830 | − ret = m5mols_update_fw(sd, m5mols_sensor_power); | |
| 831 | − if (ret) | |
| 832 | − return ret; | |
| 833 | − | |
| 834 | − v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); | |
| 835 | − | |
| 836 | − ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); | |
| 837 | − if (!ret) | |
| 838 | − ret = m5mols_enable_interrupt(sd, | |
| 839 | − REG_INT_AF | REG_INT_CAPTURE); | |
| 840 | − | |
| 841 | − return ret; | |
| 842 | −} | |
| 843 | − | |
| 844 | −/* Execute the lens soft-landing algorithm */ | |
| 845 | −static int m5mols_auto_focus_stop(struct m5mols_info *info) | |
| 846 | −{ | |
| 847 | − int ret; | |
| 848 | − | |
| 849 | − ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); | |
| 850 | − if (!ret) | |
| 851 | − ret = m5mols_write(&info->sd, AF_MODE, REG_AF_POWEROFF); | |
| 852 | − if (!ret) | |
| 853 | − ret = m5mols_busy_wait(&info->sd, SYSTEM_STATUS, REG_AF_IDLE, | |
| 854 | − 0xff, -1); | |
| 855 | − return ret; | |
| 856 | −} | |
| 857 | − | |
| 858 | −/** | |
| 859 | − * m5mols_s_power - Main sensor power control function | |
| 860 | − * @sd: sub-device, as pointed by struct v4l2_subdev | |
| 861 | − * @on: if true, powers on the device; powers off otherwise. | |
| 862 | − * | |
| 863 | − * To prevent breaking the lens when the sensor is powered off the Soft-Landing | |
| 864 | − * algorithm is called where available. The Soft-Landing algorithm availability | |
| 865 | − * dependends on the firmware provider. | |
| 866 | − */ | |
| 867 | −static int m5mols_s_power(struct v4l2_subdev *sd, int on) | |
| 868 | −{ | |
| 869 | − struct m5mols_info *info = to_m5mols(sd); | |
| 870 | − int ret; | |
| 871 | − | |
| 872 | − mutex_lock(&info->lock); | |
| 873 | − | |
| 874 | − if (on) { | |
| 875 | − ret = m5mols_sensor_power(info, true); | |
| 876 | − if (!ret) | |
| 877 | − ret = m5mols_fw_start(sd); | |
| 878 | − } else { | |
| 879 | − if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { | |
| 880 | − ret = m5mols_set_mode(info, REG_MONITOR); | |
| 881 | − if (!ret) | |
| 882 | − ret = m5mols_auto_focus_stop(info); | |
| 883 | − if (ret < 0) | |
| 884 | − v4l2_warn(sd, "Soft landing lens failed\n"); | |
| 885 | − } | |
| 886 | − ret = m5mols_sensor_power(info, false); | |
| 887 | − | |
| 888 | − info->ctrl_sync = 0; | |
| 889 | − } | |
| 890 | − | |
| 891 | − mutex_unlock(&info->lock); | |
| 892 | − return ret; | |
| 893 | −} | |
| 894 | − | |
| 895 | −static int m5mols_log_status(struct v4l2_subdev *sd) | |
| 896 | −{ | |
| 897 | − struct m5mols_info *info = to_m5mols(sd); | |
| 898 | − | |
| 899 | − v4l2_ctrl_handler_log_status(&info->handle, sd->name); | |
| 900 | − | |
| 901 | − return 0; | |
| 902 | −} | |
| 903 | − | |
| 904 | −static const struct v4l2_subdev_core_ops m5mols_core_ops = { | |
| 905 | − .s_power = m5mols_s_power, | |
| 906 | − .log_status = m5mols_log_status, | |
| 907 | −}; | |
| 908 | − | |
| 909 | −/* | |
| 910 | − * V4L2 subdev internal operations | |
| 911 | − */ | |
| 912 | −static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 913 | −{ | |
| 914 | − struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, | |
| 915 | − fh->state, | |
| 916 | − 0); | |
| 917 | − | |
| 918 | − *format = m5mols_default_ffmt[0]; | |
| 919 | − return 0; | |
| 920 | −} | |
| 921 | − | |
| 922 | −static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = { | |
| 923 | − .open = m5mols_open, | |
| 924 | −}; | |
| 925 | − | |
| 926 | −static const struct v4l2_subdev_ops m5mols_ops = { | |
| 927 | − .core = &m5mols_core_ops, | |
| 928 | − .pad = &m5mols_pad_ops, | |
| 929 | − .video = &m5mols_video_ops, | |
| 930 | −}; | |
| 931 | − | |
| 932 | −static irqreturn_t m5mols_irq_handler(int irq, void *data) | |
| 933 | −{ | |
| 934 | − struct m5mols_info *info = to_m5mols(data); | |
| 935 | − | |
| 936 | − atomic_set(&info->irq_done, 1); | |
| 937 | − wake_up_interruptible(&info->irq_waitq); | |
| 938 | − | |
| 939 | − return IRQ_HANDLED; | |
| 940 | −} | |
| 941 | − | |
| 942 | −static int m5mols_probe(struct i2c_client *client) | |
| 943 | −{ | |
| 944 | − const struct m5mols_platform_data *pdata = client->dev.platform_data; | |
| 945 | − struct m5mols_info *info; | |
| 946 | − struct v4l2_subdev *sd; | |
| 947 | − int ret; | |
| 948 | − | |
| 949 | − if (pdata == NULL) { | |
| 950 | − dev_err(&client->dev, "No platform data\n"); | |
| 951 | − return -EINVAL; | |
| 952 | − } | |
| 953 | − | |
| 954 | − if (!client->irq) { | |
| 955 | − dev_err(&client->dev, "Interrupt not assigned\n"); | |
| 956 | − return -EINVAL; | |
| 957 | − } | |
| 958 | − | |
| 959 | − info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); | |
| 960 | − if (!info) | |
| 961 | − return -ENOMEM; | |
| 962 | − | |
| 963 | − /* This asserts reset, descriptor shall have polarity specified */ | |
| 964 | − info->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); | |
| 965 | − if (IS_ERR(info->reset)) | |
| 966 | − return PTR_ERR(info->reset); | |
| 967 | − /* Notice: the "N" in M5MOLS_NRST implies active low */ | |
| 968 | − gpiod_set_consumer_name(info->reset, "M5MOLS_NRST"); | |
| 969 | − | |
| 970 | − info->pdata = pdata; | |
| 971 | − info->set_power = pdata->set_power; | |
| 972 | − | |
| 973 | − ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), | |
| 974 | − supplies); | |
| 975 | − if (ret) { | |
| 976 | − dev_err(&client->dev, "Failed to get regulators: %d\n", ret); | |
| 977 | − return ret; | |
| 978 | − } | |
| 979 | − | |
| 980 | − sd = &info->sd; | |
| 981 | − v4l2_i2c_subdev_init(sd, client, &m5mols_ops); | |
| 982 | − /* Static name; NEVER use in new drivers! */ | |
| 983 | − strscpy(sd->name, MODULE_NAME, sizeof(sd->name)); | |
| 984 | − sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 985 | − | |
| 986 | − sd->internal_ops = &m5mols_subdev_internal_ops; | |
| 987 | − info->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 988 | − ret = media_entity_pads_init(&sd->entity, 1, &info->pad); | |
| 989 | − if (ret < 0) | |
| 990 | − return ret; | |
| 991 | − sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 992 | − | |
| 993 | − init_waitqueue_head(&info->irq_waitq); | |
| 994 | − mutex_init(&info->lock); | |
| 995 | − | |
| 996 | − ret = devm_request_irq(&client->dev, client->irq, m5mols_irq_handler, | |
| 997 | − IRQF_TRIGGER_RISING, MODULE_NAME, sd); | |
| 998 | − if (ret) { | |
| 999 | − dev_err(&client->dev, "Interrupt request failed: %d\n", ret); | |
| 1000 | − goto error; | |
| 1001 | − } | |
| 1002 | − info->res_type = M5MOLS_RESTYPE_MONITOR; | |
| 1003 | − info->ffmt[0] = m5mols_default_ffmt[0]; | |
| 1004 | − info->ffmt[1] = m5mols_default_ffmt[1]; | |
| 1005 | − | |
| 1006 | − ret = m5mols_sensor_power(info, true); | |
| 1007 | − if (ret) | |
| 1008 | − goto error; | |
| 1009 | − | |
| 1010 | − ret = m5mols_fw_start(sd); | |
| 1011 | − if (!ret) | |
| 1012 | − ret = m5mols_init_controls(sd); | |
| 1013 | − | |
| 1014 | − ret = m5mols_sensor_power(info, false); | |
| 1015 | − if (!ret) | |
| 1016 | − return 0; | |
| 1017 | −error: | |
| 1018 | − media_entity_cleanup(&sd->entity); | |
| 1019 | − return ret; | |
| 1020 | −} | |
| 1021 | − | |
| 1022 | −static void m5mols_remove(struct i2c_client *client) | |
| 1023 | −{ | |
| 1024 | − struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1025 | − | |
| 1026 | − v4l2_device_unregister_subdev(sd); | |
| 1027 | − v4l2_ctrl_handler_free(sd->ctrl_handler); | |
| 1028 | − media_entity_cleanup(&sd->entity); | |
| 1029 | −} | |
| 1030 | − | |
| 1031 | −static const struct i2c_device_id m5mols_id[] = { | |
| 1032 | − { MODULE_NAME, 0 }, | |
| 1033 | − { }, | |
| 1034 | −}; | |
| 1035 | −MODULE_DEVICE_TABLE(i2c, m5mols_id); | |
| 1036 | − | |
| 1037 | −static struct i2c_driver m5mols_i2c_driver = { | |
| 1038 | − .driver = { | |
| 1039 | − .name = MODULE_NAME, | |
| 1040 | − }, | |
| 1041 | − .probe_new = m5mols_probe, | |
| 1042 | − .remove = m5mols_remove, | |
| 1043 | − .id_table = m5mols_id, | |
| 1044 | −}; | |
| 1045 | − | |
| 1046 | −module_i2c_driver(m5mols_i2c_driver); | |
| 1047 | − | |
| 1048 | −MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); | |
| 1049 | −MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); | |
| 1050 | −MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); | |
| 1051 | −MODULE_LICENSE("GPL"); | |
| @@ -1,359 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/* | |
| 3 | − * Register map for M-5MOLS 8M Pixel camera sensor with ISP | |
| 4 | − * | |
| 5 | − * Copyright (C) 2011 Samsung Electronics Co., Ltd. | |
| 6 | − * Author: HeungJun Kim <riverful.kim@samsung.com> | |
| 7 | − * | |
| 8 | − * Copyright (C) 2009 Samsung Electronics Co., Ltd. | |
| 9 | − * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#ifndef M5MOLS_REG_H | |
| 13 | −#define M5MOLS_REG_H | |
| 14 | − | |
| 15 | −#define M5MOLS_I2C_MAX_SIZE 4 | |
| 16 | −#define M5MOLS_BYTE_READ 0x01 | |
| 17 | −#define M5MOLS_BYTE_WRITE 0x02 | |
| 18 | − | |
| 19 | −#define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff) | |
| 20 | −#define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff) | |
| 21 | −#define I2C_SIZE(__reg_s) ((__reg_s) & 0xff) | |
| 22 | −#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s) | |
| 23 | − | |
| 24 | −/* | |
| 25 | − * Category section register | |
| 26 | − * | |
| 27 | − * The category means set including relevant command of M-5MOLS. | |
| 28 | − */ | |
| 29 | −#define CAT_SYSTEM 0x00 | |
| 30 | −#define CAT_PARAM 0x01 | |
| 31 | −#define CAT_MONITOR 0x02 | |
| 32 | −#define CAT_AE 0x03 | |
| 33 | −#define CAT_WB 0x06 | |
| 34 | −#define CAT_EXIF 0x07 | |
| 35 | −#define CAT_FD 0x09 | |
| 36 | −#define CAT_LENS 0x0a | |
| 37 | −#define CAT_CAPT_PARM 0x0b | |
| 38 | −#define CAT_CAPT_CTRL 0x0c | |
| 39 | −#define CAT_FLASH 0x0f /* related to FW, revisions, booting */ | |
| 40 | − | |
| 41 | −/* | |
| 42 | − * Category 0 - SYSTEM mode | |
| 43 | − * | |
| 44 | − * The SYSTEM mode in the M-5MOLS means area available to handle with the whole | |
| 45 | − * & all-round system of sensor. It deals with version/interrupt/setting mode & | |
| 46 | − * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by | |
| 47 | − * packaging & manufacturer, even the customer and project code. And the | |
| 48 | − * function details may vary among them. The version information helps to | |
| 49 | − * determine what methods shall be used in the driver. | |
| 50 | − * | |
| 51 | − * There is many registers between customer version address and awb one. For | |
| 52 | − * more specific contents, see definition if file m5mols.h. | |
| 53 | − */ | |
| 54 | −#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, 0x00, 1) | |
| 55 | −#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, 0x01, 1) | |
| 56 | −#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, 0x02, 2) | |
| 57 | −#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, 0x04, 2) | |
| 58 | −#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, 0x06, 2) | |
| 59 | −#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, 0x08, 2) | |
| 60 | − | |
| 61 | −#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, 0x0b, 1) | |
| 62 | −#define REG_SYSINIT 0x00 /* SYSTEM mode */ | |
| 63 | −#define REG_PARAMETER 0x01 /* PARAMETER mode */ | |
| 64 | −#define REG_MONITOR 0x02 /* MONITOR mode */ | |
| 65 | −#define REG_CAPTURE 0x03 /* CAPTURE mode */ | |
| 66 | − | |
| 67 | −#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) | |
| 68 | −#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, 0x0a, 1) | |
| 69 | −#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ | |
| 70 | −#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ | |
| 71 | −#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ | |
| 72 | −/* SYSTEM mode status */ | |
| 73 | −#define SYSTEM_STATUS I2C_REG(CAT_SYSTEM, 0x0c, 1) | |
| 74 | − | |
| 75 | −/* Interrupt pending register */ | |
| 76 | −#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, 0x10, 1) | |
| 77 | −/* interrupt enable register */ | |
| 78 | −#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, 0x11, 1) | |
| 79 | −#define REG_INT_MODE (1 << 0) | |
| 80 | −#define REG_INT_AF (1 << 1) | |
| 81 | −#define REG_INT_ZOOM (1 << 2) | |
| 82 | −#define REG_INT_CAPTURE (1 << 3) | |
| 83 | −#define REG_INT_FRAMESYNC (1 << 4) | |
| 84 | −#define REG_INT_FD (1 << 5) | |
| 85 | −#define REG_INT_LENS_INIT (1 << 6) | |
| 86 | −#define REG_INT_SOUND (1 << 7) | |
| 87 | −#define REG_INT_MASK 0x0f | |
| 88 | − | |
| 89 | −/* | |
| 90 | − * category 1 - PARAMETER mode | |
| 91 | − * | |
| 92 | − * This category supports function of camera features of M-5MOLS. It means we | |
| 93 | − * can handle with preview(MONITOR) resolution size/frame per second/interface | |
| 94 | − * between the sensor and the Application Processor/even the image effect. | |
| 95 | − */ | |
| 96 | − | |
| 97 | −/* Resolution in the MONITOR mode */ | |
| 98 | −#define PARM_MON_SIZE I2C_REG(CAT_PARAM, 0x01, 1) | |
| 99 | − | |
| 100 | −/* Frame rate */ | |
| 101 | −#define PARM_MON_FPS I2C_REG(CAT_PARAM, 0x02, 1) | |
| 102 | −#define REG_FPS_30 0x02 | |
| 103 | − | |
| 104 | −/* Video bus between the sensor and a host processor */ | |
| 105 | −#define PARM_INTERFACE I2C_REG(CAT_PARAM, 0x00, 1) | |
| 106 | −#define REG_INTERFACE_MIPI 0x02 | |
| 107 | − | |
| 108 | −/* Image effects */ | |
| 109 | −#define PARM_EFFECT I2C_REG(CAT_PARAM, 0x0b, 1) | |
| 110 | −#define REG_EFFECT_OFF 0x00 | |
| 111 | −#define REG_EFFECT_NEGA 0x01 | |
| 112 | −#define REG_EFFECT_EMBOSS 0x06 | |
| 113 | −#define REG_EFFECT_OUTLINE 0x07 | |
| 114 | −#define REG_EFFECT_WATERCOLOR 0x08 | |
| 115 | − | |
| 116 | −/* | |
| 117 | − * Category 2 - MONITOR mode | |
| 118 | − * | |
| 119 | − * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another | |
| 120 | − * mode named "Preview", but this preview mode is used at the case specific | |
| 121 | − * vider-recording mode. This mmode supports only YUYV format. On the other | |
| 122 | − * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are | |
| 123 | − * another options like zoom/color effect(different with effect in PARAMETER | |
| 124 | − * mode)/anti hand shaking algorithm. | |
| 125 | − */ | |
| 126 | − | |
| 127 | −/* Target digital zoom position */ | |
| 128 | −#define MON_ZOOM I2C_REG(CAT_MONITOR, 0x01, 1) | |
| 129 | − | |
| 130 | −/* CR value for color effect */ | |
| 131 | −#define MON_CFIXR I2C_REG(CAT_MONITOR, 0x0a, 1) | |
| 132 | −/* CB value for color effect */ | |
| 133 | −#define MON_CFIXB I2C_REG(CAT_MONITOR, 0x09, 1) | |
| 134 | −#define REG_CFIXB_SEPIA 0xd8 | |
| 135 | −#define REG_CFIXR_SEPIA 0x18 | |
| 136 | − | |
| 137 | −#define MON_EFFECT I2C_REG(CAT_MONITOR, 0x0b, 1) | |
| 138 | −#define REG_COLOR_EFFECT_OFF 0x00 | |
| 139 | −#define REG_COLOR_EFFECT_ON 0x01 | |
| 140 | − | |
| 141 | −/* Chroma enable */ | |
| 142 | −#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, 0x10, 1) | |
| 143 | −/* Chroma level */ | |
| 144 | −#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, 0x0f, 1) | |
| 145 | −#define REG_CHROMA_OFF 0x00 | |
| 146 | −#define REG_CHROMA_ON 0x01 | |
| 147 | − | |
| 148 | −/* Sharpness on/off */ | |
| 149 | −#define MON_EDGE_EN I2C_REG(CAT_MONITOR, 0x12, 1) | |
| 150 | −/* Sharpness level */ | |
| 151 | −#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, 0x11, 1) | |
| 152 | −#define REG_EDGE_OFF 0x00 | |
| 153 | −#define REG_EDGE_ON 0x01 | |
| 154 | − | |
| 155 | −/* Set color tone (contrast) */ | |
| 156 | −#define MON_TONE_CTL I2C_REG(CAT_MONITOR, 0x25, 1) | |
| 157 | − | |
| 158 | −/* | |
| 159 | − * Category 3 - Auto Exposure | |
| 160 | − * | |
| 161 | − * The M-5MOLS exposure capbility is detailed as which is similar to digital | |
| 162 | − * camera. This category supports AE locking/various AE mode(range of exposure) | |
| 163 | − * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the | |
| 164 | − * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be | |
| 165 | − * different. So, this category also provide getting the max/min values. And, | |
| 166 | − * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. | |
| 167 | − */ | |
| 168 | − | |
| 169 | −/* Auto Exposure locking */ | |
| 170 | −#define AE_LOCK I2C_REG(CAT_AE, 0x00, 1) | |
| 171 | −#define REG_AE_UNLOCK 0x00 | |
| 172 | −#define REG_AE_LOCK 0x01 | |
| 173 | − | |
| 174 | −/* Auto Exposure algorithm mode */ | |
| 175 | −#define AE_MODE I2C_REG(CAT_AE, 0x01, 1) | |
| 176 | −#define REG_AE_OFF 0x00 /* AE off */ | |
| 177 | −#define REG_AE_ALL 0x01 /* calc AE in all block integral */ | |
| 178 | −#define REG_AE_CENTER 0x03 /* calc AE in center weighted */ | |
| 179 | −#define REG_AE_SPOT 0x06 /* calc AE in specific spot */ | |
| 180 | − | |
| 181 | −#define AE_ISO I2C_REG(CAT_AE, 0x05, 1) | |
| 182 | −#define REG_ISO_AUTO 0x00 | |
| 183 | −#define REG_ISO_50 0x01 | |
| 184 | −#define REG_ISO_100 0x02 | |
| 185 | −#define REG_ISO_200 0x03 | |
| 186 | −#define REG_ISO_400 0x04 | |
| 187 | −#define REG_ISO_800 0x05 | |
| 188 | − | |
| 189 | −/* EV (scenemode) preset for MONITOR */ | |
| 190 | −#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, 0x0a, 1) | |
| 191 | −/* EV (scenemode) preset for CAPTURE */ | |
| 192 | −#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, 0x0b, 1) | |
| 193 | −#define REG_SCENE_NORMAL 0x00 | |
| 194 | −#define REG_SCENE_PORTRAIT 0x01 | |
| 195 | −#define REG_SCENE_LANDSCAPE 0x02 | |
| 196 | −#define REG_SCENE_SPORTS 0x03 | |
| 197 | −#define REG_SCENE_PARTY_INDOOR 0x04 | |
| 198 | −#define REG_SCENE_BEACH_SNOW 0x05 | |
| 199 | −#define REG_SCENE_SUNSET 0x06 | |
| 200 | −#define REG_SCENE_DAWN_DUSK 0x07 | |
| 201 | −#define REG_SCENE_FALL 0x08 | |
| 202 | −#define REG_SCENE_NIGHT 0x09 | |
| 203 | −#define REG_SCENE_AGAINST_LIGHT 0x0a | |
| 204 | −#define REG_SCENE_FIRE 0x0b | |
| 205 | −#define REG_SCENE_TEXT 0x0c | |
| 206 | −#define REG_SCENE_CANDLE 0x0d | |
| 207 | − | |
| 208 | −/* Manual gain in MONITOR mode */ | |
| 209 | −#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, 0x12, 2) | |
| 210 | −/* Maximum gain in MONITOR mode */ | |
| 211 | −#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, 0x1a, 2) | |
| 212 | −/* Manual gain in CAPTURE mode */ | |
| 213 | −#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, 0x26, 2) | |
| 214 | − | |
| 215 | −#define AE_INDEX I2C_REG(CAT_AE, 0x38, 1) | |
| 216 | −#define REG_AE_INDEX_20_NEG 0x00 | |
| 217 | −#define REG_AE_INDEX_15_NEG 0x01 | |
| 218 | −#define REG_AE_INDEX_10_NEG 0x02 | |
| 219 | −#define REG_AE_INDEX_05_NEG 0x03 | |
| 220 | −#define REG_AE_INDEX_00 0x04 | |
| 221 | −#define REG_AE_INDEX_05_POS 0x05 | |
| 222 | −#define REG_AE_INDEX_10_POS 0x06 | |
| 223 | −#define REG_AE_INDEX_15_POS 0x07 | |
| 224 | −#define REG_AE_INDEX_20_POS 0x08 | |
| 225 | − | |
| 226 | −/* | |
| 227 | − * Category 6 - White Balance | |
| 228 | − */ | |
| 229 | − | |
| 230 | −/* Auto Whitebalance locking */ | |
| 231 | −#define AWB_LOCK I2C_REG(CAT_WB, 0x00, 1) | |
| 232 | −#define REG_AWB_UNLOCK 0x00 | |
| 233 | −#define REG_AWB_LOCK 0x01 | |
| 234 | − | |
| 235 | −#define AWB_MODE I2C_REG(CAT_WB, 0x02, 1) | |
| 236 | −#define REG_AWB_AUTO 0x01 /* AWB off */ | |
| 237 | −#define REG_AWB_PRESET 0x02 /* AWB preset */ | |
| 238 | − | |
| 239 | −/* Manual WB (preset) */ | |
| 240 | −#define AWB_MANUAL I2C_REG(CAT_WB, 0x03, 1) | |
| 241 | −#define REG_AWB_INCANDESCENT 0x01 | |
| 242 | −#define REG_AWB_FLUORESCENT_1 0x02 | |
| 243 | −#define REG_AWB_FLUORESCENT_2 0x03 | |
| 244 | −#define REG_AWB_DAYLIGHT 0x04 | |
| 245 | −#define REG_AWB_CLOUDY 0x05 | |
| 246 | −#define REG_AWB_SHADE 0x06 | |
| 247 | −#define REG_AWB_HORIZON 0x07 | |
| 248 | −#define REG_AWB_LEDLIGHT 0x09 | |
| 249 | − | |
| 250 | −/* | |
| 251 | − * Category 7 - EXIF information | |
| 252 | − */ | |
| 253 | −#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, 0x00, 4) | |
| 254 | −#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, 0x04, 4) | |
| 255 | −#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, 0x08, 4) | |
| 256 | −#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, 0x0c, 4) | |
| 257 | −#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, 0x10, 4) | |
| 258 | −#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, 0x14, 4) | |
| 259 | −#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, 0x18, 4) | |
| 260 | −#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, 0x1c, 4) | |
| 261 | −#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, 0x20, 4) | |
| 262 | −#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, 0x24, 4) | |
| 263 | −#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, 0x28, 2) | |
| 264 | −#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, 0x2a, 2) | |
| 265 | −#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, 0x2c, 2) | |
| 266 | −#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, 0x2e, 2) | |
| 267 | − | |
| 268 | −/* | |
| 269 | − * Category 9 - Face Detection | |
| 270 | − */ | |
| 271 | −#define FD_CTL I2C_REG(CAT_FD, 0x00, 1) | |
| 272 | −#define BIT_FD_EN 0 | |
| 273 | −#define BIT_FD_DRAW_FACE_FRAME 4 | |
| 274 | −#define BIT_FD_DRAW_SMILE_LVL 6 | |
| 275 | −#define REG_FD(shift) (1 << shift) | |
| 276 | −#define REG_FD_OFF 0x0 | |
| 277 | − | |
| 278 | −/* | |
| 279 | − * Category A - Lens Parameter | |
| 280 | − */ | |
| 281 | −#define AF_MODE I2C_REG(CAT_LENS, 0x01, 1) | |
| 282 | −#define REG_AF_NORMAL 0x00 /* Normal AF, one time */ | |
| 283 | −#define REG_AF_MACRO 0x01 /* Macro AF, one time */ | |
| 284 | −#define REG_AF_POWEROFF 0x07 | |
| 285 | − | |
| 286 | −#define AF_EXECUTE I2C_REG(CAT_LENS, 0x02, 1) | |
| 287 | −#define REG_AF_STOP 0x00 | |
| 288 | −#define REG_AF_EXE_AUTO 0x01 | |
| 289 | −#define REG_AF_EXE_CAF 0x02 | |
| 290 | − | |
| 291 | −#define AF_STATUS I2C_REG(CAT_LENS, 0x03, 1) | |
| 292 | −#define REG_AF_FAIL 0x00 | |
| 293 | −#define REG_AF_SUCCESS 0x02 | |
| 294 | −#define REG_AF_IDLE 0x04 | |
| 295 | −#define REG_AF_BUSY 0x05 | |
| 296 | − | |
| 297 | −#define AF_VERSION I2C_REG(CAT_LENS, 0x0a, 1) | |
| 298 | − | |
| 299 | −/* | |
| 300 | − * Category B - CAPTURE Parameter | |
| 301 | − */ | |
| 302 | −#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, 0x00, 1) | |
| 303 | −#define REG_YUV422 0x00 | |
| 304 | −#define REG_BAYER10 0x05 | |
| 305 | −#define REG_BAYER8 0x06 | |
| 306 | −#define REG_JPEG 0x10 | |
| 307 | − | |
| 308 | −#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1) | |
| 309 | −#define CAPP_JPEG_SIZE_MAX I2C_REG(CAT_CAPT_PARM, 0x0f, 4) | |
| 310 | −#define CAPP_JPEG_RATIO I2C_REG(CAT_CAPT_PARM, 0x17, 1) | |
| 311 | − | |
| 312 | −#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1) | |
| 313 | −#define REG_MCC_OFF 0x00 | |
| 314 | −#define REG_MCC_NORMAL 0x01 | |
| 315 | − | |
| 316 | −#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, 0x2c, 1) | |
| 317 | −#define REG_WDR_OFF 0x00 | |
| 318 | −#define REG_WDR_ON 0x01 | |
| 319 | −#define REG_WDR_AUTO 0x02 | |
| 320 | − | |
| 321 | −#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, 0x40, 1) | |
| 322 | −#define REG_LIGHT_OFF 0x00 | |
| 323 | −#define REG_LIGHT_ON 0x01 | |
| 324 | −#define REG_LIGHT_AUTO 0x02 | |
| 325 | − | |
| 326 | −#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, 0x41, 1) | |
| 327 | −#define REG_FLASH_OFF 0x00 | |
| 328 | −#define REG_FLASH_ON 0x01 | |
| 329 | −#define REG_FLASH_AUTO 0x02 | |
| 330 | − | |
| 331 | −/* | |
| 332 | − * Category C - CAPTURE Control | |
| 333 | − */ | |
| 334 | −#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, 0x00, 1) | |
| 335 | −#define REG_CAP_NONE 0x00 | |
| 336 | −#define REG_CAP_ANTI_SHAKE 0x02 | |
| 337 | − | |
| 338 | −/* Select single- or multi-shot capture */ | |
| 339 | −#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, 0x06, 1) | |
| 340 | − | |
| 341 | −#define CAPC_START I2C_REG(CAT_CAPT_CTRL, 0x09, 1) | |
| 342 | −#define REG_CAP_START_MAIN 0x01 | |
| 343 | −#define REG_CAP_START_THUMB 0x03 | |
| 344 | − | |
| 345 | −#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, 0x0d, 4) | |
| 346 | −#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, 0x11, 4) | |
| 347 | − | |
| 348 | −/* | |
| 349 | − * Category F - Flash | |
| 350 | − * | |
| 351 | − * This mode provides functions about internal flash stuff and system startup. | |
| 352 | − */ | |
| 353 | − | |
| 354 | −/* Starts internal ARM core booting after power-up */ | |
| 355 | −#define FLASH_CAM_START I2C_REG(CAT_FLASH, 0x12, 1) | |
| 356 | −#define REG_START_ARM_BOOT 0x01 /* write value */ | |
| 357 | −#define REG_IN_FLASH_MODE 0x00 /* read value */ | |
| 358 | − | |
| 359 | −#endif /* M5MOLS_REG_H */ | |
| @@ -1122,6 +1122,7 @@ err_async: · 1121 unmodified lines | ||
| 1122 | 1122 | static void max9286_v4l2_unregister(struct max9286_priv *priv) |
| 1123 | 1123 | { |
| 1124 | 1124 | fwnode_handle_put(priv->sd.fwnode); |
| 1125 | + v4l2_ctrl_handler_free(&priv->ctrls); | |
| 1125 | 1126 | v4l2_async_unregister_subdev(&priv->sd); |
| 1126 | 1127 | max9286_v4l2_notifier_unregister(priv); |
| 1127 | 1128 | } |
| @@ -1,891 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Driver for MT9M032 CMOS Image Sensor from Micron | |
| 4 | − * | |
| 5 | − * Copyright (C) 2010-2011 Lund Engineering | |
| 6 | − * Contact: Gil Lund <gwlund@lundeng.com> | |
| 7 | − * Author: Martin Hostettler <martin@neutronstar.dyndns.org> | |
| 8 | − */ | |
| 9 | − | |
| 10 | −#include <linux/delay.h> | |
| 11 | −#include <linux/i2c.h> | |
| 12 | −#include <linux/init.h> | |
| 13 | −#include <linux/kernel.h> | |
| 14 | −#include <linux/math64.h> | |
| 15 | −#include <linux/module.h> | |
| 16 | −#include <linux/mutex.h> | |
| 17 | −#include <linux/slab.h> | |
| 18 | −#include <linux/v4l2-mediabus.h> | |
| 19 | − | |
| 20 | −#include <media/media-entity.h> | |
| 21 | −#include <media/i2c/mt9m032.h> | |
| 22 | −#include <media/v4l2-ctrls.h> | |
| 23 | −#include <media/v4l2-device.h> | |
| 24 | −#include <media/v4l2-subdev.h> | |
| 25 | − | |
| 26 | −#include "aptina-pll.h" | |
| 27 | − | |
| 28 | −/* | |
| 29 | − * width and height include active boundary and black parts | |
| 30 | − * | |
| 31 | − * column 0- 15 active boundary | |
| 32 | − * column 16-1455 image | |
| 33 | − * column 1456-1471 active boundary | |
| 34 | − * column 1472-1599 black | |
| 35 | − * | |
| 36 | − * row 0- 51 black | |
| 37 | − * row 53- 59 active boundary | |
| 38 | − * row 60-1139 image | |
| 39 | − * row 1140-1147 active boundary | |
| 40 | − * row 1148-1151 black | |
| 41 | − */ | |
| 42 | − | |
| 43 | −#define MT9M032_PIXEL_ARRAY_WIDTH 1600 | |
| 44 | −#define MT9M032_PIXEL_ARRAY_HEIGHT 1152 | |
| 45 | − | |
| 46 | −#define MT9M032_CHIP_VERSION 0x00 | |
| 47 | −#define MT9M032_CHIP_VERSION_VALUE 0x1402 | |
| 48 | −#define MT9M032_ROW_START 0x01 | |
| 49 | −#define MT9M032_ROW_START_MIN 0 | |
| 50 | −#define MT9M032_ROW_START_MAX 1152 | |
| 51 | −#define MT9M032_ROW_START_DEF 60 | |
| 52 | −#define MT9M032_COLUMN_START 0x02 | |
| 53 | −#define MT9M032_COLUMN_START_MIN 0 | |
| 54 | −#define MT9M032_COLUMN_START_MAX 1600 | |
| 55 | −#define MT9M032_COLUMN_START_DEF 16 | |
| 56 | −#define MT9M032_ROW_SIZE 0x03 | |
| 57 | −#define MT9M032_ROW_SIZE_MIN 32 | |
| 58 | −#define MT9M032_ROW_SIZE_MAX 1152 | |
| 59 | −#define MT9M032_ROW_SIZE_DEF 1080 | |
| 60 | −#define MT9M032_COLUMN_SIZE 0x04 | |
| 61 | −#define MT9M032_COLUMN_SIZE_MIN 32 | |
| 62 | −#define MT9M032_COLUMN_SIZE_MAX 1600 | |
| 63 | −#define MT9M032_COLUMN_SIZE_DEF 1440 | |
| 64 | −#define MT9M032_HBLANK 0x05 | |
| 65 | −#define MT9M032_VBLANK 0x06 | |
| 66 | −#define MT9M032_VBLANK_MAX 0x7ff | |
| 67 | −#define MT9M032_SHUTTER_WIDTH_HIGH 0x08 | |
| 68 | −#define MT9M032_SHUTTER_WIDTH_LOW 0x09 | |
| 69 | −#define MT9M032_SHUTTER_WIDTH_MIN 1 | |
| 70 | −#define MT9M032_SHUTTER_WIDTH_MAX 1048575 | |
| 71 | −#define MT9M032_SHUTTER_WIDTH_DEF 1943 | |
| 72 | −#define MT9M032_PIX_CLK_CTRL 0x0a | |
| 73 | −#define MT9M032_PIX_CLK_CTRL_INV_PIXCLK 0x8000 | |
| 74 | −#define MT9M032_RESTART 0x0b | |
| 75 | −#define MT9M032_RESET 0x0d | |
| 76 | −#define MT9M032_PLL_CONFIG1 0x11 | |
| 77 | −#define MT9M032_PLL_CONFIG1_PREDIV_MASK 0x3f | |
| 78 | −#define MT9M032_PLL_CONFIG1_MUL_SHIFT 8 | |
| 79 | −#define MT9M032_READ_MODE1 0x1e | |
| 80 | −#define MT9M032_READ_MODE1_OUTPUT_BAD_FRAMES (1 << 13) | |
| 81 | −#define MT9M032_READ_MODE1_MAINTAIN_FRAME_RATE (1 << 12) | |
| 82 | −#define MT9M032_READ_MODE1_XOR_LINE_VALID (1 << 11) | |
| 83 | −#define MT9M032_READ_MODE1_CONT_LINE_VALID (1 << 10) | |
| 84 | −#define MT9M032_READ_MODE1_INVERT_TRIGGER (1 << 9) | |
| 85 | −#define MT9M032_READ_MODE1_SNAPSHOT (1 << 8) | |
| 86 | −#define MT9M032_READ_MODE1_GLOBAL_RESET (1 << 7) | |
| 87 | −#define MT9M032_READ_MODE1_BULB_EXPOSURE (1 << 6) | |
| 88 | −#define MT9M032_READ_MODE1_INVERT_STROBE (1 << 5) | |
| 89 | −#define MT9M032_READ_MODE1_STROBE_ENABLE (1 << 4) | |
| 90 | −#define MT9M032_READ_MODE1_STROBE_START_TRIG1 (0 << 2) | |
| 91 | −#define MT9M032_READ_MODE1_STROBE_START_EXP (1 << 2) | |
| 92 | −#define MT9M032_READ_MODE1_STROBE_START_SHUTTER (2 << 2) | |
| 93 | −#define MT9M032_READ_MODE1_STROBE_START_TRIG2 (3 << 2) | |
| 94 | −#define MT9M032_READ_MODE1_STROBE_END_TRIG1 (0 << 0) | |
| 95 | −#define MT9M032_READ_MODE1_STROBE_END_EXP (1 << 0) | |
| 96 | −#define MT9M032_READ_MODE1_STROBE_END_SHUTTER (2 << 0) | |
| 97 | −#define MT9M032_READ_MODE1_STROBE_END_TRIG2 (3 << 0) | |
| 98 | −#define MT9M032_READ_MODE2 0x20 | |
| 99 | −#define MT9M032_READ_MODE2_VFLIP_SHIFT 15 | |
| 100 | −#define MT9M032_READ_MODE2_HFLIP_SHIFT 14 | |
| 101 | −#define MT9M032_READ_MODE2_ROW_BLC 0x40 | |
| 102 | −#define MT9M032_GAIN_GREEN1 0x2b | |
| 103 | −#define MT9M032_GAIN_BLUE 0x2c | |
| 104 | −#define MT9M032_GAIN_RED 0x2d | |
| 105 | −#define MT9M032_GAIN_GREEN2 0x2e | |
| 106 | − | |
| 107 | −/* write only */ | |
| 108 | −#define MT9M032_GAIN_ALL 0x35 | |
| 109 | −#define MT9M032_GAIN_DIGITAL_MASK 0x7f | |
| 110 | −#define MT9M032_GAIN_DIGITAL_SHIFT 8 | |
| 111 | −#define MT9M032_GAIN_AMUL_SHIFT 6 | |
| 112 | −#define MT9M032_GAIN_ANALOG_MASK 0x3f | |
| 113 | −#define MT9M032_FORMATTER1 0x9e | |
| 114 | −#define MT9M032_FORMATTER1_PLL_P1_6 (1 << 8) | |
| 115 | −#define MT9M032_FORMATTER1_PARALLEL (1 << 12) | |
| 116 | −#define MT9M032_FORMATTER2 0x9f | |
| 117 | −#define MT9M032_FORMATTER2_DOUT_EN 0x1000 | |
| 118 | −#define MT9M032_FORMATTER2_PIXCLK_EN 0x2000 | |
| 119 | − | |
| 120 | −/* | |
| 121 | − * The available MT9M032 datasheet is missing documentation for register 0x10 | |
| 122 | − * MT9P031 seems to be close enough, so use constants from that datasheet for | |
| 123 | − * now. | |
| 124 | − * But keep the name MT9P031 to remind us, that this isn't really confirmed | |
| 125 | − * for this sensor. | |
| 126 | − */ | |
| 127 | −#define MT9P031_PLL_CONTROL 0x10 | |
| 128 | −#define MT9P031_PLL_CONTROL_PWROFF 0x0050 | |
| 129 | −#define MT9P031_PLL_CONTROL_PWRON 0x0051 | |
| 130 | −#define MT9P031_PLL_CONTROL_USEPLL 0x0052 | |
| 131 | − | |
| 132 | −struct mt9m032 { | |
| 133 | − struct v4l2_subdev subdev; | |
| 134 | − struct media_pad pad; | |
| 135 | − struct mt9m032_platform_data *pdata; | |
| 136 | − | |
| 137 | − unsigned int pix_clock; | |
| 138 | − | |
| 139 | − struct v4l2_ctrl_handler ctrls; | |
| 140 | − struct { | |
| 141 | − struct v4l2_ctrl *hflip; | |
| 142 | − struct v4l2_ctrl *vflip; | |
| 143 | − }; | |
| 144 | − | |
| 145 | − struct mutex lock; /* Protects streaming, format, interval and crop */ | |
| 146 | − | |
| 147 | − bool streaming; | |
| 148 | − | |
| 149 | − struct v4l2_mbus_framefmt format; | |
| 150 | − struct v4l2_rect crop; | |
| 151 | − struct v4l2_fract frame_interval; | |
| 152 | −}; | |
| 153 | − | |
| 154 | −#define to_mt9m032(sd) container_of(sd, struct mt9m032, subdev) | |
| 155 | −#define to_dev(sensor) \ | |
| 156 | − (&((struct i2c_client *)v4l2_get_subdevdata(&(sensor)->subdev))->dev) | |
| 157 | − | |
| 158 | −static int mt9m032_read(struct i2c_client *client, u8 reg) | |
| 159 | −{ | |
| 160 | − return i2c_smbus_read_word_swapped(client, reg); | |
| 161 | −} | |
| 162 | − | |
| 163 | −static int mt9m032_write(struct i2c_client *client, u8 reg, const u16 data) | |
| 164 | −{ | |
| 165 | − return i2c_smbus_write_word_swapped(client, reg, data); | |
| 166 | −} | |
| 167 | − | |
| 168 | −static u32 mt9m032_row_time(struct mt9m032 *sensor, unsigned int width) | |
| 169 | −{ | |
| 170 | − unsigned int effective_width; | |
| 171 | − u32 ns; | |
| 172 | − | |
| 173 | − effective_width = width + 716; /* empirical value */ | |
| 174 | − ns = div_u64(1000000000ULL * effective_width, sensor->pix_clock); | |
| 175 | − dev_dbg(to_dev(sensor), "MT9M032 line time: %u ns\n", ns); | |
| 176 | − return ns; | |
| 177 | −} | |
| 178 | − | |
| 179 | −static int mt9m032_update_timing(struct mt9m032 *sensor, | |
| 180 | − struct v4l2_fract *interval) | |
| 181 | −{ | |
| 182 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 183 | − struct v4l2_rect *crop = &sensor->crop; | |
| 184 | − unsigned int min_vblank; | |
| 185 | − unsigned int vblank; | |
| 186 | − u32 row_time; | |
| 187 | − | |
| 188 | − if (!interval) | |
| 189 | − interval = &sensor->frame_interval; | |
| 190 | − | |
| 191 | − row_time = mt9m032_row_time(sensor, crop->width); | |
| 192 | − | |
| 193 | − vblank = div_u64(1000000000ULL * interval->numerator, | |
| 194 | − (u64)row_time * interval->denominator) | |
| 195 | − - crop->height; | |
| 196 | − | |
| 197 | − if (vblank > MT9M032_VBLANK_MAX) { | |
| 198 | − /* hardware limits to 11 bit values */ | |
| 199 | − interval->denominator = 1000; | |
| 200 | − interval->numerator = | |
| 201 | − div_u64((crop->height + MT9M032_VBLANK_MAX) * | |
| 202 | − (u64)row_time * interval->denominator, | |
| 203 | − 1000000000ULL); | |
| 204 | − vblank = div_u64(1000000000ULL * interval->numerator, | |
| 205 | − (u64)row_time * interval->denominator) | |
| 206 | − - crop->height; | |
| 207 | − } | |
| 208 | − /* enforce minimal 1.6ms blanking time. */ | |
| 209 | − min_vblank = 1600000 / row_time; | |
| 210 | − vblank = clamp_t(unsigned int, vblank, min_vblank, MT9M032_VBLANK_MAX); | |
| 211 | − | |
| 212 | − return mt9m032_write(client, MT9M032_VBLANK, vblank); | |
| 213 | −} | |
| 214 | − | |
| 215 | −static int mt9m032_update_geom_timing(struct mt9m032 *sensor) | |
| 216 | −{ | |
| 217 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 218 | − int ret; | |
| 219 | − | |
| 220 | − ret = mt9m032_write(client, MT9M032_COLUMN_SIZE, | |
| 221 | − sensor->crop.width - 1); | |
| 222 | − if (!ret) | |
| 223 | − ret = mt9m032_write(client, MT9M032_ROW_SIZE, | |
| 224 | − sensor->crop.height - 1); | |
| 225 | − if (!ret) | |
| 226 | − ret = mt9m032_write(client, MT9M032_COLUMN_START, | |
| 227 | − sensor->crop.left); | |
| 228 | − if (!ret) | |
| 229 | − ret = mt9m032_write(client, MT9M032_ROW_START, | |
| 230 | − sensor->crop.top); | |
| 231 | − if (!ret) | |
| 232 | − ret = mt9m032_update_timing(sensor, NULL); | |
| 233 | − return ret; | |
| 234 | −} | |
| 235 | − | |
| 236 | −static int update_formatter2(struct mt9m032 *sensor, bool streaming) | |
| 237 | −{ | |
| 238 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 239 | − u16 reg_val = MT9M032_FORMATTER2_DOUT_EN | |
| 240 | − | 0x0070; /* parts reserved! */ | |
| 241 | − /* possibly for changing to 14-bit mode */ | |
| 242 | − | |
| 243 | − if (streaming) | |
| 244 | − reg_val |= MT9M032_FORMATTER2_PIXCLK_EN; /* pixclock enable */ | |
| 245 | − | |
| 246 | − return mt9m032_write(client, MT9M032_FORMATTER2, reg_val); | |
| 247 | −} | |
| 248 | − | |
| 249 | −static int mt9m032_setup_pll(struct mt9m032 *sensor) | |
| 250 | −{ | |
| 251 | − static const struct aptina_pll_limits limits = { | |
| 252 | − .ext_clock_min = 8000000, | |
| 253 | − .ext_clock_max = 16500000, | |
| 254 | − .int_clock_min = 2000000, | |
| 255 | − .int_clock_max = 24000000, | |
| 256 | − .out_clock_min = 322000000, | |
| 257 | − .out_clock_max = 693000000, | |
| 258 | − .pix_clock_max = 99000000, | |
| 259 | − .n_min = 1, | |
| 260 | − .n_max = 64, | |
| 261 | − .m_min = 16, | |
| 262 | − .m_max = 255, | |
| 263 | − .p1_min = 6, | |
| 264 | − .p1_max = 7, | |
| 265 | − }; | |
| 266 | − | |
| 267 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 268 | − struct mt9m032_platform_data *pdata = sensor->pdata; | |
| 269 | − struct aptina_pll pll; | |
| 270 | − u16 reg_val; | |
| 271 | − int ret; | |
| 272 | − | |
| 273 | − pll.ext_clock = pdata->ext_clock; | |
| 274 | − pll.pix_clock = pdata->pix_clock; | |
| 275 | − | |
| 276 | − ret = aptina_pll_calculate(&client->dev, &limits, &pll); | |
| 277 | − if (ret < 0) | |
| 278 | − return ret; | |
| 279 | − | |
| 280 | − sensor->pix_clock = pdata->pix_clock; | |
| 281 | − | |
| 282 | − ret = mt9m032_write(client, MT9M032_PLL_CONFIG1, | |
| 283 | − (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) | | |
| 284 | − ((pll.n - 1) & MT9M032_PLL_CONFIG1_PREDIV_MASK)); | |
| 285 | − if (!ret) | |
| 286 | − ret = mt9m032_write(client, MT9P031_PLL_CONTROL, | |
| 287 | − MT9P031_PLL_CONTROL_PWRON | | |
| 288 | − MT9P031_PLL_CONTROL_USEPLL); | |
| 289 | − if (!ret) /* more reserved, Continuous, Master Mode */ | |
| 290 | − ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8000 | | |
| 291 | − MT9M032_READ_MODE1_STROBE_START_EXP | | |
| 292 | − MT9M032_READ_MODE1_STROBE_END_SHUTTER); | |
| 293 | − if (!ret) { | |
| 294 | − reg_val = (pll.p1 == 6 ? MT9M032_FORMATTER1_PLL_P1_6 : 0) | |
| 295 | − | MT9M032_FORMATTER1_PARALLEL | 0x001e; /* 14-bit */ | |
| 296 | − ret = mt9m032_write(client, MT9M032_FORMATTER1, reg_val); | |
| 297 | − } | |
| 298 | − | |
| 299 | − return ret; | |
| 300 | −} | |
| 301 | − | |
| 302 | −/* ----------------------------------------------------------------------------- | |
| 303 | − * Subdev pad operations | |
| 304 | − */ | |
| 305 | − | |
| 306 | −static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, | |
| 307 | − struct v4l2_subdev_state *sd_state, | |
| 308 | − struct v4l2_subdev_mbus_code_enum *code) | |
| 309 | −{ | |
| 310 | − if (code->index != 0) | |
| 311 | − return -EINVAL; | |
| 312 | − | |
| 313 | − code->code = MEDIA_BUS_FMT_Y8_1X8; | |
| 314 | − return 0; | |
| 315 | −} | |
| 316 | − | |
| 317 | −static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, | |
| 318 | − struct v4l2_subdev_state *sd_state, | |
| 319 | − struct v4l2_subdev_frame_size_enum *fse) | |
| 320 | −{ | |
| 321 | − if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8) | |
| 322 | − return -EINVAL; | |
| 323 | − | |
| 324 | − fse->min_width = MT9M032_COLUMN_SIZE_DEF; | |
| 325 | − fse->max_width = MT9M032_COLUMN_SIZE_DEF; | |
| 326 | − fse->min_height = MT9M032_ROW_SIZE_DEF; | |
| 327 | − fse->max_height = MT9M032_ROW_SIZE_DEF; | |
| 328 | − | |
| 329 | − return 0; | |
| 330 | −} | |
| 331 | − | |
| 332 | −/** | |
| 333 | − * __mt9m032_get_pad_crop() - get crop rect | |
| 334 | − * @sensor: pointer to the sensor struct | |
| 335 | − * @sd_state: v4l2_subdev_state for getting the try crop rect from | |
| 336 | − * @which: select try or active crop rect | |
| 337 | − * | |
| 338 | − * Returns a pointer the current active or fh relative try crop rect | |
| 339 | − */ | |
| 340 | −static struct v4l2_rect * | |
| 341 | −__mt9m032_get_pad_crop(struct mt9m032 *sensor, | |
| 342 | − struct v4l2_subdev_state *sd_state, | |
| 343 | − enum v4l2_subdev_format_whence which) | |
| 344 | −{ | |
| 345 | − switch (which) { | |
| 346 | − case V4L2_SUBDEV_FORMAT_TRY: | |
| 347 | − return v4l2_subdev_get_try_crop(&sensor->subdev, sd_state, 0); | |
| 348 | − case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 349 | − return &sensor->crop; | |
| 350 | − default: | |
| 351 | − return NULL; | |
| 352 | − } | |
| 353 | −} | |
| 354 | − | |
| 355 | −/** | |
| 356 | − * __mt9m032_get_pad_format() - get format | |
| 357 | − * @sensor: pointer to the sensor struct | |
| 358 | − * @sd_state: v4l2_subdev_state for getting the try format from | |
| 359 | − * @which: select try or active format | |
| 360 | − * | |
| 361 | − * Returns a pointer the current active or fh relative try format | |
| 362 | − */ | |
| 363 | −static struct v4l2_mbus_framefmt * | |
| 364 | −__mt9m032_get_pad_format(struct mt9m032 *sensor, | |
| 365 | − struct v4l2_subdev_state *sd_state, | |
| 366 | − enum v4l2_subdev_format_whence which) | |
| 367 | −{ | |
| 368 | − switch (which) { | |
| 369 | − case V4L2_SUBDEV_FORMAT_TRY: | |
| 370 | − return v4l2_subdev_get_try_format(&sensor->subdev, sd_state, | |
| 371 | − 0); | |
| 372 | − case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 373 | − return &sensor->format; | |
| 374 | − default: | |
| 375 | − return NULL; | |
| 376 | − } | |
| 377 | −} | |
| 378 | − | |
| 379 | −static int mt9m032_get_pad_format(struct v4l2_subdev *subdev, | |
| 380 | − struct v4l2_subdev_state *sd_state, | |
| 381 | − struct v4l2_subdev_format *fmt) | |
| 382 | −{ | |
| 383 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 384 | − | |
| 385 | − mutex_lock(&sensor->lock); | |
| 386 | − fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which); | |
| 387 | − mutex_unlock(&sensor->lock); | |
| 388 | − | |
| 389 | − return 0; | |
| 390 | −} | |
| 391 | − | |
| 392 | −static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, | |
| 393 | − struct v4l2_subdev_state *sd_state, | |
| 394 | − struct v4l2_subdev_format *fmt) | |
| 395 | −{ | |
| 396 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 397 | − int ret; | |
| 398 | − | |
| 399 | − mutex_lock(&sensor->lock); | |
| 400 | − | |
| 401 | − if (sensor->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | |
| 402 | − ret = -EBUSY; | |
| 403 | − goto done; | |
| 404 | − } | |
| 405 | − | |
| 406 | − /* Scaling is not supported, the format is thus fixed. */ | |
| 407 | − fmt->format = *__mt9m032_get_pad_format(sensor, sd_state, fmt->which); | |
| 408 | − ret = 0; | |
| 409 | − | |
| 410 | −done: | |
| 411 | − mutex_unlock(&sensor->lock); | |
| 412 | − return ret; | |
| 413 | −} | |
| 414 | − | |
| 415 | −static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev, | |
| 416 | − struct v4l2_subdev_state *sd_state, | |
| 417 | − struct v4l2_subdev_selection *sel) | |
| 418 | −{ | |
| 419 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 420 | − | |
| 421 | − if (sel->target != V4L2_SEL_TGT_CROP) | |
| 422 | − return -EINVAL; | |
| 423 | − | |
| 424 | − mutex_lock(&sensor->lock); | |
| 425 | − sel->r = *__mt9m032_get_pad_crop(sensor, sd_state, sel->which); | |
| 426 | − mutex_unlock(&sensor->lock); | |
| 427 | − | |
| 428 | − return 0; | |
| 429 | −} | |
| 430 | − | |
| 431 | −static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev, | |
| 432 | − struct v4l2_subdev_state *sd_state, | |
| 433 | − struct v4l2_subdev_selection *sel) | |
| 434 | −{ | |
| 435 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 436 | − struct v4l2_mbus_framefmt *format; | |
| 437 | − struct v4l2_rect *__crop; | |
| 438 | − struct v4l2_rect rect; | |
| 439 | − int ret = 0; | |
| 440 | − | |
| 441 | − if (sel->target != V4L2_SEL_TGT_CROP) | |
| 442 | − return -EINVAL; | |
| 443 | − | |
| 444 | − mutex_lock(&sensor->lock); | |
| 445 | − | |
| 446 | − if (sensor->streaming && sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | |
| 447 | − ret = -EBUSY; | |
| 448 | − goto done; | |
| 449 | − } | |
| 450 | − | |
| 451 | − /* Clamp the crop rectangle boundaries and align them to a multiple of 2 | |
| 452 | − * pixels to ensure a GRBG Bayer pattern. | |
| 453 | − */ | |
| 454 | − rect.left = clamp(ALIGN(sel->r.left, 2), MT9M032_COLUMN_START_MIN, | |
| 455 | − MT9M032_COLUMN_START_MAX); | |
| 456 | − rect.top = clamp(ALIGN(sel->r.top, 2), MT9M032_ROW_START_MIN, | |
| 457 | − MT9M032_ROW_START_MAX); | |
| 458 | − rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), | |
| 459 | − MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX); | |
| 460 | − rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), | |
| 461 | − MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX); | |
| 462 | − | |
| 463 | − rect.width = min_t(unsigned int, rect.width, | |
| 464 | − MT9M032_PIXEL_ARRAY_WIDTH - rect.left); | |
| 465 | − rect.height = min_t(unsigned int, rect.height, | |
| 466 | − MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); | |
| 467 | − | |
| 468 | − __crop = __mt9m032_get_pad_crop(sensor, sd_state, sel->which); | |
| 469 | − | |
| 470 | − if (rect.width != __crop->width || rect.height != __crop->height) { | |
| 471 | − /* Reset the output image size if the crop rectangle size has | |
| 472 | − * been modified. | |
| 473 | − */ | |
| 474 | − format = __mt9m032_get_pad_format(sensor, sd_state, | |
| 475 | − sel->which); | |
| 476 | − format->width = rect.width; | |
| 477 | − format->height = rect.height; | |
| 478 | − } | |
| 479 | − | |
| 480 | − *__crop = rect; | |
| 481 | − sel->r = rect; | |
| 482 | − | |
| 483 | − if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 484 | − ret = mt9m032_update_geom_timing(sensor); | |
| 485 | − | |
| 486 | −done: | |
| 487 | − mutex_unlock(&sensor->lock); | |
| 488 | − return ret; | |
| 489 | −} | |
| 490 | − | |
| 491 | −static int mt9m032_get_frame_interval(struct v4l2_subdev *subdev, | |
| 492 | − struct v4l2_subdev_frame_interval *fi) | |
| 493 | −{ | |
| 494 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 495 | − | |
| 496 | − mutex_lock(&sensor->lock); | |
| 497 | − memset(fi, 0, sizeof(*fi)); | |
| 498 | − fi->interval = sensor->frame_interval; | |
| 499 | − mutex_unlock(&sensor->lock); | |
| 500 | − | |
| 501 | − return 0; | |
| 502 | −} | |
| 503 | − | |
| 504 | −static int mt9m032_set_frame_interval(struct v4l2_subdev *subdev, | |
| 505 | − struct v4l2_subdev_frame_interval *fi) | |
| 506 | −{ | |
| 507 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 508 | − int ret; | |
| 509 | − | |
| 510 | − mutex_lock(&sensor->lock); | |
| 511 | − | |
| 512 | − if (sensor->streaming) { | |
| 513 | − ret = -EBUSY; | |
| 514 | − goto done; | |
| 515 | − } | |
| 516 | − | |
| 517 | − /* Avoid divisions by 0. */ | |
| 518 | − if (fi->interval.denominator == 0) | |
| 519 | − fi->interval.denominator = 1; | |
| 520 | − | |
| 521 | − ret = mt9m032_update_timing(sensor, &fi->interval); | |
| 522 | − if (!ret) | |
| 523 | − sensor->frame_interval = fi->interval; | |
| 524 | − | |
| 525 | −done: | |
| 526 | − mutex_unlock(&sensor->lock); | |
| 527 | − return ret; | |
| 528 | −} | |
| 529 | − | |
| 530 | −static int mt9m032_s_stream(struct v4l2_subdev *subdev, int streaming) | |
| 531 | −{ | |
| 532 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 533 | − int ret; | |
| 534 | − | |
| 535 | − mutex_lock(&sensor->lock); | |
| 536 | − ret = update_formatter2(sensor, streaming); | |
| 537 | − if (!ret) | |
| 538 | − sensor->streaming = streaming; | |
| 539 | − mutex_unlock(&sensor->lock); | |
| 540 | − | |
| 541 | − return ret; | |
| 542 | −} | |
| 543 | − | |
| 544 | −/* ----------------------------------------------------------------------------- | |
| 545 | − * V4L2 subdev core operations | |
| 546 | − */ | |
| 547 | − | |
| 548 | −#ifdef CONFIG_VIDEO_ADV_DEBUG | |
| 549 | −static int mt9m032_g_register(struct v4l2_subdev *sd, | |
| 550 | − struct v4l2_dbg_register *reg) | |
| 551 | −{ | |
| 552 | − struct mt9m032 *sensor = to_mt9m032(sd); | |
| 553 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 554 | − int val; | |
| 555 | − | |
| 556 | − if (reg->reg > 0xff) | |
| 557 | − return -EINVAL; | |
| 558 | − | |
| 559 | − val = mt9m032_read(client, reg->reg); | |
| 560 | − if (val < 0) | |
| 561 | − return -EIO; | |
| 562 | − | |
| 563 | − reg->size = 2; | |
| 564 | − reg->val = val; | |
| 565 | − | |
| 566 | − return 0; | |
| 567 | −} | |
| 568 | − | |
| 569 | −static int mt9m032_s_register(struct v4l2_subdev *sd, | |
| 570 | − const struct v4l2_dbg_register *reg) | |
| 571 | −{ | |
| 572 | − struct mt9m032 *sensor = to_mt9m032(sd); | |
| 573 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 574 | − | |
| 575 | − if (reg->reg > 0xff) | |
| 576 | − return -EINVAL; | |
| 577 | − | |
| 578 | − return mt9m032_write(client, reg->reg, reg->val); | |
| 579 | −} | |
| 580 | −#endif | |
| 581 | − | |
| 582 | −/* ----------------------------------------------------------------------------- | |
| 583 | − * V4L2 subdev control operations | |
| 584 | − */ | |
| 585 | − | |
| 586 | −static int update_read_mode2(struct mt9m032 *sensor, bool vflip, bool hflip) | |
| 587 | −{ | |
| 588 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 589 | − int reg_val = (vflip << MT9M032_READ_MODE2_VFLIP_SHIFT) | |
| 590 | − | (hflip << MT9M032_READ_MODE2_HFLIP_SHIFT) | |
| 591 | − | MT9M032_READ_MODE2_ROW_BLC | |
| 592 | − | 0x0007; | |
| 593 | − | |
| 594 | − return mt9m032_write(client, MT9M032_READ_MODE2, reg_val); | |
| 595 | −} | |
| 596 | − | |
| 597 | −static int mt9m032_set_gain(struct mt9m032 *sensor, s32 val) | |
| 598 | −{ | |
| 599 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 600 | − int digital_gain_val; /* in 1/8th (0..127) */ | |
| 601 | − int analog_mul; /* 0 or 1 */ | |
| 602 | − int analog_gain_val; /* in 1/16th. (0..63) */ | |
| 603 | − u16 reg_val; | |
| 604 | − | |
| 605 | − digital_gain_val = 51; /* from setup example */ | |
| 606 | − | |
| 607 | − if (val < 63) { | |
| 608 | − analog_mul = 0; | |
| 609 | − analog_gain_val = val; | |
| 610 | − } else { | |
| 611 | − analog_mul = 1; | |
| 612 | − analog_gain_val = val / 2; | |
| 613 | − } | |
| 614 | − | |
| 615 | − /* a_gain = (1 + analog_mul) + (analog_gain_val + 1) / 16 */ | |
| 616 | − /* overall_gain = a_gain * (1 + digital_gain_val / 8) */ | |
| 617 | − | |
| 618 | − reg_val = ((digital_gain_val & MT9M032_GAIN_DIGITAL_MASK) | |
| 619 | − << MT9M032_GAIN_DIGITAL_SHIFT) | |
| 620 | − | ((analog_mul & 1) << MT9M032_GAIN_AMUL_SHIFT) | |
| 621 | − | (analog_gain_val & MT9M032_GAIN_ANALOG_MASK); | |
| 622 | − | |
| 623 | − return mt9m032_write(client, MT9M032_GAIN_ALL, reg_val); | |
| 624 | −} | |
| 625 | − | |
| 626 | −static int mt9m032_try_ctrl(struct v4l2_ctrl *ctrl) | |
| 627 | −{ | |
| 628 | − if (ctrl->id == V4L2_CID_GAIN && ctrl->val >= 63) { | |
| 629 | − /* round because of multiplier used for values >= 63 */ | |
| 630 | − ctrl->val &= ~1; | |
| 631 | − } | |
| 632 | − | |
| 633 | − return 0; | |
| 634 | −} | |
| 635 | − | |
| 636 | −static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl) | |
| 637 | −{ | |
| 638 | − struct mt9m032 *sensor = | |
| 639 | − container_of(ctrl->handler, struct mt9m032, ctrls); | |
| 640 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); | |
| 641 | − int ret; | |
| 642 | − | |
| 643 | − switch (ctrl->id) { | |
| 644 | − case V4L2_CID_GAIN: | |
| 645 | − return mt9m032_set_gain(sensor, ctrl->val); | |
| 646 | − | |
| 647 | − case V4L2_CID_HFLIP: | |
| 648 | − /* case V4L2_CID_VFLIP: -- In the same cluster */ | |
| 649 | − return update_read_mode2(sensor, sensor->vflip->val, | |
| 650 | − sensor->hflip->val); | |
| 651 | − | |
| 652 | − case V4L2_CID_EXPOSURE: | |
| 653 | − ret = mt9m032_write(client, MT9M032_SHUTTER_WIDTH_HIGH, | |
| 654 | − (ctrl->val >> 16) & 0xffff); | |
| 655 | − if (ret < 0) | |
| 656 | − return ret; | |
| 657 | − | |
| 658 | − return mt9m032_write(client, MT9M032_SHUTTER_WIDTH_LOW, | |
| 659 | − ctrl->val & 0xffff); | |
| 660 | − } | |
| 661 | − | |
| 662 | − return 0; | |
| 663 | −} | |
| 664 | − | |
| 665 | −static const struct v4l2_ctrl_ops mt9m032_ctrl_ops = { | |
| 666 | − .s_ctrl = mt9m032_set_ctrl, | |
| 667 | − .try_ctrl = mt9m032_try_ctrl, | |
| 668 | −}; | |
| 669 | − | |
| 670 | −/* -------------------------------------------------------------------------- */ | |
| 671 | − | |
| 672 | −static const struct v4l2_subdev_core_ops mt9m032_core_ops = { | |
| 673 | −#ifdef CONFIG_VIDEO_ADV_DEBUG | |
| 674 | − .g_register = mt9m032_g_register, | |
| 675 | − .s_register = mt9m032_s_register, | |
| 676 | −#endif | |
| 677 | −}; | |
| 678 | − | |
| 679 | −static const struct v4l2_subdev_video_ops mt9m032_video_ops = { | |
| 680 | − .s_stream = mt9m032_s_stream, | |
| 681 | − .g_frame_interval = mt9m032_get_frame_interval, | |
| 682 | − .s_frame_interval = mt9m032_set_frame_interval, | |
| 683 | −}; | |
| 684 | − | |
| 685 | −static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = { | |
| 686 | − .enum_mbus_code = mt9m032_enum_mbus_code, | |
| 687 | − .enum_frame_size = mt9m032_enum_frame_size, | |
| 688 | − .get_fmt = mt9m032_get_pad_format, | |
| 689 | − .set_fmt = mt9m032_set_pad_format, | |
| 690 | − .set_selection = mt9m032_set_pad_selection, | |
| 691 | − .get_selection = mt9m032_get_pad_selection, | |
| 692 | −}; | |
| 693 | − | |
| 694 | −static const struct v4l2_subdev_ops mt9m032_ops = { | |
| 695 | − .core = &mt9m032_core_ops, | |
| 696 | − .video = &mt9m032_video_ops, | |
| 697 | − .pad = &mt9m032_pad_ops, | |
| 698 | −}; | |
| 699 | − | |
| 700 | −/* ----------------------------------------------------------------------------- | |
| 701 | − * Driver initialization and probing | |
| 702 | − */ | |
| 703 | − | |
| 704 | −static int mt9m032_probe(struct i2c_client *client) | |
| 705 | −{ | |
| 706 | − struct mt9m032_platform_data *pdata = client->dev.platform_data; | |
| 707 | − struct i2c_adapter *adapter = client->adapter; | |
| 708 | − struct mt9m032 *sensor; | |
| 709 | − int chip_version; | |
| 710 | − int ret; | |
| 711 | − | |
| 712 | − if (pdata == NULL) { | |
| 713 | − dev_err(&client->dev, "No platform data\n"); | |
| 714 | − return -EINVAL; | |
| 715 | − } | |
| 716 | − | |
| 717 | − if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | |
| 718 | − dev_warn(&client->dev, | |
| 719 | − "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | |
| 720 | − return -EIO; | |
| 721 | − } | |
| 722 | − | |
| 723 | − if (!client->dev.platform_data) | |
| 724 | − return -ENODEV; | |
| 725 | − | |
| 726 | − sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); | |
| 727 | − if (sensor == NULL) | |
| 728 | − return -ENOMEM; | |
| 729 | − | |
| 730 | − mutex_init(&sensor->lock); | |
| 731 | − | |
| 732 | − sensor->pdata = pdata; | |
| 733 | − | |
| 734 | − v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops); | |
| 735 | − sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 736 | − | |
| 737 | − chip_version = mt9m032_read(client, MT9M032_CHIP_VERSION); | |
| 738 | − if (chip_version != MT9M032_CHIP_VERSION_VALUE) { | |
| 739 | − dev_err(&client->dev, "MT9M032 not detected, wrong version " | |
| 740 | − "0x%04x\n", chip_version); | |
| 741 | − ret = -ENODEV; | |
| 742 | − goto error_sensor; | |
| 743 | − } | |
| 744 | − | |
| 745 | − dev_info(&client->dev, "MT9M032 detected at address 0x%02x\n", | |
| 746 | − client->addr); | |
| 747 | − | |
| 748 | − sensor->frame_interval.numerator = 1; | |
| 749 | − sensor->frame_interval.denominator = 30; | |
| 750 | − | |
| 751 | − sensor->crop.left = MT9M032_COLUMN_START_DEF; | |
| 752 | − sensor->crop.top = MT9M032_ROW_START_DEF; | |
| 753 | − sensor->crop.width = MT9M032_COLUMN_SIZE_DEF; | |
| 754 | − sensor->crop.height = MT9M032_ROW_SIZE_DEF; | |
| 755 | − | |
| 756 | − sensor->format.width = sensor->crop.width; | |
| 757 | − sensor->format.height = sensor->crop.height; | |
| 758 | − sensor->format.code = MEDIA_BUS_FMT_Y8_1X8; | |
| 759 | − sensor->format.field = V4L2_FIELD_NONE; | |
| 760 | − sensor->format.colorspace = V4L2_COLORSPACE_SRGB; | |
| 761 | − | |
| 762 | − v4l2_ctrl_handler_init(&sensor->ctrls, 5); | |
| 763 | − | |
| 764 | − v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, | |
| 765 | − V4L2_CID_GAIN, 0, 127, 1, 64); | |
| 766 | − | |
| 767 | − sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, | |
| 768 | − &mt9m032_ctrl_ops, | |
| 769 | − V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 770 | − sensor->vflip = v4l2_ctrl_new_std(&sensor->ctrls, | |
| 771 | − &mt9m032_ctrl_ops, | |
| 772 | − V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 773 | − | |
| 774 | − v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, | |
| 775 | − V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN, | |
| 776 | − MT9M032_SHUTTER_WIDTH_MAX, 1, | |
| 777 | − MT9M032_SHUTTER_WIDTH_DEF); | |
| 778 | − v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, | |
| 779 | − V4L2_CID_PIXEL_RATE, pdata->pix_clock, | |
| 780 | − pdata->pix_clock, 1, pdata->pix_clock); | |
| 781 | − | |
| 782 | − if (sensor->ctrls.error) { | |
| 783 | − ret = sensor->ctrls.error; | |
| 784 | − dev_err(&client->dev, "control initialization error %d\n", ret); | |
| 785 | − goto error_ctrl; | |
| 786 | − } | |
| 787 | − | |
| 788 | − v4l2_ctrl_cluster(2, &sensor->hflip); | |
| 789 | − | |
| 790 | − sensor->subdev.ctrl_handler = &sensor->ctrls; | |
| 791 | − sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 792 | − sensor->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 793 | − ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); | |
| 794 | − if (ret < 0) | |
| 795 | − goto error_ctrl; | |
| 796 | − | |
| 797 | − ret = mt9m032_write(client, MT9M032_RESET, 1); /* reset on */ | |
| 798 | − if (ret < 0) | |
| 799 | − goto error_entity; | |
| 800 | − ret = mt9m032_write(client, MT9M032_RESET, 0); /* reset off */ | |
| 801 | − if (ret < 0) | |
| 802 | − goto error_entity; | |
| 803 | − | |
| 804 | − ret = mt9m032_setup_pll(sensor); | |
| 805 | − if (ret < 0) | |
| 806 | − goto error_entity; | |
| 807 | − usleep_range(10000, 11000); | |
| 808 | − | |
| 809 | − ret = v4l2_ctrl_handler_setup(&sensor->ctrls); | |
| 810 | − if (ret < 0) | |
| 811 | − goto error_entity; | |
| 812 | − | |
| 813 | − /* SIZE */ | |
| 814 | − ret = mt9m032_update_geom_timing(sensor); | |
| 815 | − if (ret < 0) | |
| 816 | − goto error_entity; | |
| 817 | − | |
| 818 | − ret = mt9m032_write(client, 0x41, 0x0000); /* reserved !!! */ | |
| 819 | − if (ret < 0) | |
| 820 | − goto error_entity; | |
| 821 | − ret = mt9m032_write(client, 0x42, 0x0003); /* reserved !!! */ | |
| 822 | − if (ret < 0) | |
| 823 | − goto error_entity; | |
| 824 | − ret = mt9m032_write(client, 0x43, 0x0003); /* reserved !!! */ | |
| 825 | − if (ret < 0) | |
| 826 | − goto error_entity; | |
| 827 | − ret = mt9m032_write(client, 0x7f, 0x0000); /* reserved !!! */ | |
| 828 | − if (ret < 0) | |
| 829 | − goto error_entity; | |
| 830 | − if (sensor->pdata->invert_pixclock) { | |
| 831 | − ret = mt9m032_write(client, MT9M032_PIX_CLK_CTRL, | |
| 832 | − MT9M032_PIX_CLK_CTRL_INV_PIXCLK); | |
| 833 | − if (ret < 0) | |
| 834 | − goto error_entity; | |
| 835 | − } | |
| 836 | − | |
| 837 | − ret = mt9m032_write(client, MT9M032_RESTART, 1); /* Restart on */ | |
| 838 | − if (ret < 0) | |
| 839 | − goto error_entity; | |
| 840 | − msleep(100); | |
| 841 | − ret = mt9m032_write(client, MT9M032_RESTART, 0); /* Restart off */ | |
| 842 | − if (ret < 0) | |
| 843 | − goto error_entity; | |
| 844 | − msleep(100); | |
| 845 | − ret = update_formatter2(sensor, false); | |
| 846 | − if (ret < 0) | |
| 847 | − goto error_entity; | |
| 848 | − | |
| 849 | − return ret; | |
| 850 | − | |
| 851 | −error_entity: | |
| 852 | − media_entity_cleanup(&sensor->subdev.entity); | |
| 853 | −error_ctrl: | |
| 854 | − v4l2_ctrl_handler_free(&sensor->ctrls); | |
| 855 | −error_sensor: | |
| 856 | − mutex_destroy(&sensor->lock); | |
| 857 | − return ret; | |
| 858 | −} | |
| 859 | − | |
| 860 | −static void mt9m032_remove(struct i2c_client *client) | |
| 861 | −{ | |
| 862 | − struct v4l2_subdev *subdev = i2c_get_clientdata(client); | |
| 863 | − struct mt9m032 *sensor = to_mt9m032(subdev); | |
| 864 | − | |
| 865 | − v4l2_device_unregister_subdev(subdev); | |
| 866 | − v4l2_ctrl_handler_free(&sensor->ctrls); | |
| 867 | − media_entity_cleanup(&subdev->entity); | |
| 868 | − mutex_destroy(&sensor->lock); | |
| 869 | −} | |
| 870 | − | |
| 871 | −static const struct i2c_device_id mt9m032_id_table[] = { | |
| 872 | − { MT9M032_NAME, 0 }, | |
| 873 | − { } | |
| 874 | −}; | |
| 875 | − | |
| 876 | −MODULE_DEVICE_TABLE(i2c, mt9m032_id_table); | |
| 877 | − | |
| 878 | −static struct i2c_driver mt9m032_i2c_driver = { | |
| 879 | − .driver = { | |
| 880 | − .name = MT9M032_NAME, | |
| 881 | − }, | |
| 882 | − .probe_new = mt9m032_probe, | |
| 883 | − .remove = mt9m032_remove, | |
| 884 | − .id_table = mt9m032_id_table, | |
| 885 | −}; | |
| 886 | − | |
| 887 | −module_i2c_driver(mt9m032_i2c_driver); | |
| 888 | − | |
| 889 | −MODULE_AUTHOR("Martin Hostettler <martin@neutronstar.dyndns.org>"); | |
| 890 | −MODULE_DESCRIPTION("MT9M032 camera sensor driver"); | |
| 891 | −MODULE_LICENSE("GPL v2"); | |
| @@ -1,992 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Driver for MT9T001 CMOS Image Sensor from Aptina (Micron) | |
| 4 | − * | |
| 5 | − * Copyright (C) 2010-2011, Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
| 6 | − * | |
| 7 | − * Based on the MT9M001 driver, | |
| 8 | − * | |
| 9 | − * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#include <linux/clk.h> | |
| 13 | −#include <linux/i2c.h> | |
| 14 | −#include <linux/log2.h> | |
| 15 | −#include <linux/module.h> | |
| 16 | −#include <linux/regulator/consumer.h> | |
| 17 | −#include <linux/slab.h> | |
| 18 | −#include <linux/videodev2.h> | |
| 19 | −#include <linux/v4l2-mediabus.h> | |
| 20 | − | |
| 21 | −#include <media/i2c/mt9t001.h> | |
| 22 | −#include <media/v4l2-ctrls.h> | |
| 23 | −#include <media/v4l2-device.h> | |
| 24 | −#include <media/v4l2-subdev.h> | |
| 25 | − | |
| 26 | −#define MT9T001_PIXEL_ARRAY_HEIGHT 1568 | |
| 27 | −#define MT9T001_PIXEL_ARRAY_WIDTH 2112 | |
| 28 | − | |
| 29 | −#define MT9T001_CHIP_VERSION 0x00 | |
| 30 | −#define MT9T001_CHIP_ID 0x1621 | |
| 31 | −#define MT9T001_ROW_START 0x01 | |
| 32 | −#define MT9T001_ROW_START_MIN 0 | |
| 33 | −#define MT9T001_ROW_START_DEF 20 | |
| 34 | −#define MT9T001_ROW_START_MAX 1534 | |
| 35 | −#define MT9T001_COLUMN_START 0x02 | |
| 36 | −#define MT9T001_COLUMN_START_MIN 0 | |
| 37 | −#define MT9T001_COLUMN_START_DEF 32 | |
| 38 | −#define MT9T001_COLUMN_START_MAX 2046 | |
| 39 | −#define MT9T001_WINDOW_HEIGHT 0x03 | |
| 40 | −#define MT9T001_WINDOW_HEIGHT_MIN 1 | |
| 41 | −#define MT9T001_WINDOW_HEIGHT_DEF 1535 | |
| 42 | −#define MT9T001_WINDOW_HEIGHT_MAX 1567 | |
| 43 | −#define MT9T001_WINDOW_WIDTH 0x04 | |
| 44 | −#define MT9T001_WINDOW_WIDTH_MIN 1 | |
| 45 | −#define MT9T001_WINDOW_WIDTH_DEF 2047 | |
| 46 | −#define MT9T001_WINDOW_WIDTH_MAX 2111 | |
| 47 | −#define MT9T001_HORIZONTAL_BLANKING 0x05 | |
| 48 | −#define MT9T001_HORIZONTAL_BLANKING_MIN 21 | |
| 49 | −#define MT9T001_HORIZONTAL_BLANKING_MAX 1023 | |
| 50 | −#define MT9T001_VERTICAL_BLANKING 0x06 | |
| 51 | −#define MT9T001_VERTICAL_BLANKING_MIN 3 | |
| 52 | −#define MT9T001_VERTICAL_BLANKING_MAX 1023 | |
| 53 | −#define MT9T001_OUTPUT_CONTROL 0x07 | |
| 54 | −#define MT9T001_OUTPUT_CONTROL_SYNC (1 << 0) | |
| 55 | −#define MT9T001_OUTPUT_CONTROL_CHIP_ENABLE (1 << 1) | |
| 56 | −#define MT9T001_OUTPUT_CONTROL_TEST_DATA (1 << 6) | |
| 57 | −#define MT9T001_OUTPUT_CONTROL_DEF 0x0002 | |
| 58 | −#define MT9T001_SHUTTER_WIDTH_HIGH 0x08 | |
| 59 | −#define MT9T001_SHUTTER_WIDTH_LOW 0x09 | |
| 60 | −#define MT9T001_SHUTTER_WIDTH_MIN 1 | |
| 61 | −#define MT9T001_SHUTTER_WIDTH_DEF 1561 | |
| 62 | −#define MT9T001_SHUTTER_WIDTH_MAX (1024 * 1024) | |
| 63 | −#define MT9T001_PIXEL_CLOCK 0x0a | |
| 64 | −#define MT9T001_PIXEL_CLOCK_INVERT (1 << 15) | |
| 65 | −#define MT9T001_PIXEL_CLOCK_SHIFT_MASK (7 << 8) | |
| 66 | −#define MT9T001_PIXEL_CLOCK_SHIFT_SHIFT 8 | |
| 67 | −#define MT9T001_PIXEL_CLOCK_DIVIDE_MASK (0x7f << 0) | |
| 68 | −#define MT9T001_FRAME_RESTART 0x0b | |
| 69 | −#define MT9T001_SHUTTER_DELAY 0x0c | |
| 70 | −#define MT9T001_SHUTTER_DELAY_MAX 2047 | |
| 71 | −#define MT9T001_RESET 0x0d | |
| 72 | −#define MT9T001_READ_MODE1 0x1e | |
| 73 | −#define MT9T001_READ_MODE_SNAPSHOT (1 << 8) | |
| 74 | −#define MT9T001_READ_MODE_STROBE_ENABLE (1 << 9) | |
| 75 | −#define MT9T001_READ_MODE_STROBE_WIDTH (1 << 10) | |
| 76 | −#define MT9T001_READ_MODE_STROBE_OVERRIDE (1 << 11) | |
| 77 | −#define MT9T001_READ_MODE2 0x20 | |
| 78 | −#define MT9T001_READ_MODE_BAD_FRAMES (1 << 0) | |
| 79 | −#define MT9T001_READ_MODE_LINE_VALID_CONTINUOUS (1 << 9) | |
| 80 | −#define MT9T001_READ_MODE_LINE_VALID_FRAME (1 << 10) | |
| 81 | −#define MT9T001_READ_MODE3 0x21 | |
| 82 | −#define MT9T001_READ_MODE_GLOBAL_RESET (1 << 0) | |
| 83 | −#define MT9T001_READ_MODE_GHST_CTL (1 << 1) | |
| 84 | −#define MT9T001_ROW_ADDRESS_MODE 0x22 | |
| 85 | −#define MT9T001_ROW_SKIP_MASK (7 << 0) | |
| 86 | −#define MT9T001_ROW_BIN_MASK (3 << 3) | |
| 87 | −#define MT9T001_ROW_BIN_SHIFT 3 | |
| 88 | −#define MT9T001_COLUMN_ADDRESS_MODE 0x23 | |
| 89 | −#define MT9T001_COLUMN_SKIP_MASK (7 << 0) | |
| 90 | −#define MT9T001_COLUMN_BIN_MASK (3 << 3) | |
| 91 | −#define MT9T001_COLUMN_BIN_SHIFT 3 | |
| 92 | −#define MT9T001_GREEN1_GAIN 0x2b | |
| 93 | −#define MT9T001_BLUE_GAIN 0x2c | |
| 94 | −#define MT9T001_RED_GAIN 0x2d | |
| 95 | −#define MT9T001_GREEN2_GAIN 0x2e | |
| 96 | −#define MT9T001_TEST_DATA 0x32 | |
| 97 | −#define MT9T001_GLOBAL_GAIN 0x35 | |
| 98 | −#define MT9T001_GLOBAL_GAIN_MIN 8 | |
| 99 | −#define MT9T001_GLOBAL_GAIN_MAX 1024 | |
| 100 | −#define MT9T001_BLACK_LEVEL 0x49 | |
| 101 | −#define MT9T001_ROW_BLACK_DEFAULT_OFFSET 0x4b | |
| 102 | −#define MT9T001_BLC_DELTA_THRESHOLDS 0x5d | |
| 103 | −#define MT9T001_CAL_THRESHOLDS 0x5f | |
| 104 | −#define MT9T001_GREEN1_OFFSET 0x60 | |
| 105 | −#define MT9T001_GREEN2_OFFSET 0x61 | |
| 106 | −#define MT9T001_BLACK_LEVEL_CALIBRATION 0x62 | |
| 107 | −#define MT9T001_BLACK_LEVEL_OVERRIDE (1 << 0) | |
| 108 | −#define MT9T001_BLACK_LEVEL_DISABLE_OFFSET (1 << 1) | |
| 109 | −#define MT9T001_BLACK_LEVEL_RECALCULATE (1 << 12) | |
| 110 | −#define MT9T001_BLACK_LEVEL_LOCK_RED_BLUE (1 << 13) | |
| 111 | −#define MT9T001_BLACK_LEVEL_LOCK_GREEN (1 << 14) | |
| 112 | −#define MT9T001_RED_OFFSET 0x63 | |
| 113 | −#define MT9T001_BLUE_OFFSET 0x64 | |
| 114 | − | |
| 115 | −struct mt9t001 { | |
| 116 | − struct v4l2_subdev subdev; | |
| 117 | − struct media_pad pad; | |
| 118 | − | |
| 119 | − struct clk *clk; | |
| 120 | − struct regulator_bulk_data regulators[2]; | |
| 121 | − | |
| 122 | − struct mutex power_lock; /* lock to protect power_count */ | |
| 123 | − int power_count; | |
| 124 | − | |
| 125 | − struct v4l2_mbus_framefmt format; | |
| 126 | − struct v4l2_rect crop; | |
| 127 | − | |
| 128 | − struct v4l2_ctrl_handler ctrls; | |
| 129 | − struct v4l2_ctrl *gains[4]; | |
| 130 | − | |
| 131 | − u16 output_control; | |
| 132 | − u16 black_level; | |
| 133 | −}; | |
| 134 | − | |
| 135 | −static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd) | |
| 136 | −{ | |
| 137 | − return container_of(sd, struct mt9t001, subdev); | |
| 138 | −} | |
| 139 | − | |
| 140 | −static int mt9t001_read(struct i2c_client *client, u8 reg) | |
| 141 | −{ | |
| 142 | − return i2c_smbus_read_word_swapped(client, reg); | |
| 143 | −} | |
| 144 | − | |
| 145 | −static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data) | |
| 146 | −{ | |
| 147 | − return i2c_smbus_write_word_swapped(client, reg, data); | |
| 148 | −} | |
| 149 | − | |
| 150 | −static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear, | |
| 151 | − u16 set) | |
| 152 | −{ | |
| 153 | − struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev); | |
| 154 | − u16 value = (mt9t001->output_control & ~clear) | set; | |
| 155 | − int ret; | |
| 156 | − | |
| 157 | − if (value == mt9t001->output_control) | |
| 158 | − return 0; | |
| 159 | − | |
| 160 | − ret = mt9t001_write(client, MT9T001_OUTPUT_CONTROL, value); | |
| 161 | − if (ret < 0) | |
| 162 | − return ret; | |
| 163 | − | |
| 164 | − mt9t001->output_control = value; | |
| 165 | − return 0; | |
| 166 | −} | |
| 167 | − | |
| 168 | −static int mt9t001_reset(struct mt9t001 *mt9t001) | |
| 169 | −{ | |
| 170 | − struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev); | |
| 171 | − int ret; | |
| 172 | − | |
| 173 | − /* Reset the chip and stop data read out */ | |
| 174 | − ret = mt9t001_write(client, MT9T001_RESET, 1); | |
| 175 | − if (ret < 0) | |
| 176 | − return ret; | |
| 177 | − | |
| 178 | − ret = mt9t001_write(client, MT9T001_RESET, 0); | |
| 179 | − if (ret < 0) | |
| 180 | − return ret; | |
| 181 | − | |
| 182 | − mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF; | |
| 183 | − | |
| 184 | − return mt9t001_set_output_control(mt9t001, | |
| 185 | − MT9T001_OUTPUT_CONTROL_CHIP_ENABLE, | |
| 186 | − 0); | |
| 187 | −} | |
| 188 | − | |
| 189 | −static int mt9t001_power_on(struct mt9t001 *mt9t001) | |
| 190 | −{ | |
| 191 | − int ret; | |
| 192 | − | |
| 193 | − /* Bring up the supplies */ | |
| 194 | − ret = regulator_bulk_enable(ARRAY_SIZE(mt9t001->regulators), | |
| 195 | − mt9t001->regulators); | |
| 196 | − if (ret < 0) | |
| 197 | − return ret; | |
| 198 | − | |
| 199 | − /* Enable clock */ | |
| 200 | − ret = clk_prepare_enable(mt9t001->clk); | |
| 201 | − if (ret < 0) | |
| 202 | − regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators), | |
| 203 | − mt9t001->regulators); | |
| 204 | − | |
| 205 | − return ret; | |
| 206 | −} | |
| 207 | − | |
| 208 | −static void mt9t001_power_off(struct mt9t001 *mt9t001) | |
| 209 | −{ | |
| 210 | − regulator_bulk_disable(ARRAY_SIZE(mt9t001->regulators), | |
| 211 | − mt9t001->regulators); | |
| 212 | − | |
| 213 | − clk_disable_unprepare(mt9t001->clk); | |
| 214 | −} | |
| 215 | − | |
| 216 | −static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on) | |
| 217 | −{ | |
| 218 | − struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev); | |
| 219 | − int ret; | |
| 220 | − | |
| 221 | − if (!on) { | |
| 222 | − mt9t001_power_off(mt9t001); | |
| 223 | − return 0; | |
| 224 | − } | |
| 225 | − | |
| 226 | − ret = mt9t001_power_on(mt9t001); | |
| 227 | − if (ret < 0) | |
| 228 | − return ret; | |
| 229 | − | |
| 230 | − ret = mt9t001_reset(mt9t001); | |
| 231 | − if (ret < 0) { | |
| 232 | − dev_err(&client->dev, "Failed to reset the camera\n"); | |
| 233 | − goto e_power; | |
| 234 | − } | |
| 235 | − | |
| 236 | − ret = v4l2_ctrl_handler_setup(&mt9t001->ctrls); | |
| 237 | − if (ret < 0) { | |
| 238 | − dev_err(&client->dev, "Failed to set up control handlers\n"); | |
| 239 | − goto e_power; | |
| 240 | − } | |
| 241 | − | |
| 242 | − return 0; | |
| 243 | − | |
| 244 | −e_power: | |
| 245 | − mt9t001_power_off(mt9t001); | |
| 246 | − | |
| 247 | − return ret; | |
| 248 | −} | |
| 249 | − | |
| 250 | −/* ----------------------------------------------------------------------------- | |
| 251 | − * V4L2 subdev video operations | |
| 252 | − */ | |
| 253 | − | |
| 254 | −static struct v4l2_mbus_framefmt * | |
| 255 | −__mt9t001_get_pad_format(struct mt9t001 *mt9t001, | |
| 256 | − struct v4l2_subdev_state *sd_state, | |
| 257 | − unsigned int pad, enum v4l2_subdev_format_whence which) | |
| 258 | −{ | |
| 259 | − switch (which) { | |
| 260 | − case V4L2_SUBDEV_FORMAT_TRY: | |
| 261 | − return v4l2_subdev_get_try_format(&mt9t001->subdev, sd_state, | |
| 262 | − pad); | |
| 263 | − case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 264 | − return &mt9t001->format; | |
| 265 | − default: | |
| 266 | − return NULL; | |
| 267 | − } | |
| 268 | −} | |
| 269 | − | |
| 270 | −static struct v4l2_rect * | |
| 271 | −__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, | |
| 272 | − struct v4l2_subdev_state *sd_state, | |
| 273 | − unsigned int pad, enum v4l2_subdev_format_whence which) | |
| 274 | −{ | |
| 275 | − switch (which) { | |
| 276 | − case V4L2_SUBDEV_FORMAT_TRY: | |
| 277 | − return v4l2_subdev_get_try_crop(&mt9t001->subdev, sd_state, | |
| 278 | − pad); | |
| 279 | − case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 280 | − return &mt9t001->crop; | |
| 281 | − default: | |
| 282 | − return NULL; | |
| 283 | − } | |
| 284 | −} | |
| 285 | − | |
| 286 | −static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable) | |
| 287 | −{ | |
| 288 | − const u16 mode = MT9T001_OUTPUT_CONTROL_CHIP_ENABLE; | |
| 289 | − struct i2c_client *client = v4l2_get_subdevdata(subdev); | |
| 290 | − struct mt9t001_platform_data *pdata = client->dev.platform_data; | |
| 291 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 292 | − struct v4l2_mbus_framefmt *format = &mt9t001->format; | |
| 293 | − struct v4l2_rect *crop = &mt9t001->crop; | |
| 294 | − unsigned int hratio; | |
| 295 | − unsigned int vratio; | |
| 296 | − int ret; | |
| 297 | − | |
| 298 | − if (!enable) | |
| 299 | − return mt9t001_set_output_control(mt9t001, mode, 0); | |
| 300 | − | |
| 301 | − /* Configure the pixel clock polarity */ | |
| 302 | − if (pdata->clk_pol) { | |
| 303 | − ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK, | |
| 304 | − MT9T001_PIXEL_CLOCK_INVERT); | |
| 305 | − if (ret < 0) | |
| 306 | − return ret; | |
| 307 | − } | |
| 308 | − | |
| 309 | − /* Configure the window size and row/column bin */ | |
| 310 | − hratio = DIV_ROUND_CLOSEST(crop->width, format->width); | |
| 311 | − vratio = DIV_ROUND_CLOSEST(crop->height, format->height); | |
| 312 | − | |
| 313 | − ret = mt9t001_write(client, MT9T001_ROW_ADDRESS_MODE, hratio - 1); | |
| 314 | − if (ret < 0) | |
| 315 | − return ret; | |
| 316 | − | |
| 317 | − ret = mt9t001_write(client, MT9T001_COLUMN_ADDRESS_MODE, vratio - 1); | |
| 318 | − if (ret < 0) | |
| 319 | − return ret; | |
| 320 | − | |
| 321 | − ret = mt9t001_write(client, MT9T001_COLUMN_START, crop->left); | |
| 322 | − if (ret < 0) | |
| 323 | − return ret; | |
| 324 | − | |
| 325 | − ret = mt9t001_write(client, MT9T001_ROW_START, crop->top); | |
| 326 | − if (ret < 0) | |
| 327 | − return ret; | |
| 328 | − | |
| 329 | − ret = mt9t001_write(client, MT9T001_WINDOW_WIDTH, crop->width - 1); | |
| 330 | − if (ret < 0) | |
| 331 | − return ret; | |
| 332 | − | |
| 333 | − ret = mt9t001_write(client, MT9T001_WINDOW_HEIGHT, crop->height - 1); | |
| 334 | − if (ret < 0) | |
| 335 | − return ret; | |
| 336 | − | |
| 337 | − /* Switch to master "normal" mode */ | |
| 338 | − return mt9t001_set_output_control(mt9t001, 0, mode); | |
| 339 | −} | |
| 340 | − | |
| 341 | −static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev, | |
| 342 | − struct v4l2_subdev_state *sd_state, | |
| 343 | − struct v4l2_subdev_mbus_code_enum *code) | |
| 344 | −{ | |
| 345 | − if (code->index > 0) | |
| 346 | − return -EINVAL; | |
| 347 | − | |
| 348 | − code->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 349 | − return 0; | |
| 350 | −} | |
| 351 | − | |
| 352 | −static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev, | |
| 353 | − struct v4l2_subdev_state *sd_state, | |
| 354 | − struct v4l2_subdev_frame_size_enum *fse) | |
| 355 | −{ | |
| 356 | − if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) | |
| 357 | − return -EINVAL; | |
| 358 | − | |
| 359 | − fse->min_width = (MT9T001_WINDOW_WIDTH_DEF + 1) / fse->index; | |
| 360 | − fse->max_width = fse->min_width; | |
| 361 | − fse->min_height = (MT9T001_WINDOW_HEIGHT_DEF + 1) / fse->index; | |
| 362 | − fse->max_height = fse->min_height; | |
| 363 | − | |
| 364 | − return 0; | |
| 365 | −} | |
| 366 | − | |
| 367 | −static int mt9t001_get_format(struct v4l2_subdev *subdev, | |
| 368 | − struct v4l2_subdev_state *sd_state, | |
| 369 | − struct v4l2_subdev_format *format) | |
| 370 | −{ | |
| 371 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 372 | − | |
| 373 | − format->format = *__mt9t001_get_pad_format(mt9t001, sd_state, | |
| 374 | − format->pad, | |
| 375 | − format->which); | |
| 376 | − return 0; | |
| 377 | −} | |
| 378 | − | |
| 379 | −static int mt9t001_set_format(struct v4l2_subdev *subdev, | |
| 380 | − struct v4l2_subdev_state *sd_state, | |
| 381 | − struct v4l2_subdev_format *format) | |
| 382 | −{ | |
| 383 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 384 | − struct v4l2_mbus_framefmt *__format; | |
| 385 | − struct v4l2_rect *__crop; | |
| 386 | − unsigned int width; | |
| 387 | − unsigned int height; | |
| 388 | − unsigned int hratio; | |
| 389 | − unsigned int vratio; | |
| 390 | − | |
| 391 | − __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, format->pad, | |
| 392 | − format->which); | |
| 393 | − | |
| 394 | − /* Clamp the width and height to avoid dividing by zero. */ | |
| 395 | − width = clamp_t(unsigned int, ALIGN(format->format.width, 2), | |
| 396 | − max_t(unsigned int, __crop->width / 8, | |
| 397 | − MT9T001_WINDOW_HEIGHT_MIN + 1), | |
| 398 | − __crop->width); | |
| 399 | − height = clamp_t(unsigned int, ALIGN(format->format.height, 2), | |
| 400 | − max_t(unsigned int, __crop->height / 8, | |
| 401 | − MT9T001_WINDOW_HEIGHT_MIN + 1), | |
| 402 | − __crop->height); | |
| 403 | − | |
| 404 | − hratio = DIV_ROUND_CLOSEST(__crop->width, width); | |
| 405 | − vratio = DIV_ROUND_CLOSEST(__crop->height, height); | |
| 406 | − | |
| 407 | − __format = __mt9t001_get_pad_format(mt9t001, sd_state, format->pad, | |
| 408 | − format->which); | |
| 409 | − __format->width = __crop->width / hratio; | |
| 410 | − __format->height = __crop->height / vratio; | |
| 411 | − | |
| 412 | − format->format = *__format; | |
| 413 | − | |
| 414 | − return 0; | |
| 415 | −} | |
| 416 | − | |
| 417 | −static int mt9t001_get_selection(struct v4l2_subdev *subdev, | |
| 418 | − struct v4l2_subdev_state *sd_state, | |
| 419 | − struct v4l2_subdev_selection *sel) | |
| 420 | −{ | |
| 421 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 422 | − | |
| 423 | − if (sel->target != V4L2_SEL_TGT_CROP) | |
| 424 | − return -EINVAL; | |
| 425 | − | |
| 426 | − sel->r = *__mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad, | |
| 427 | − sel->which); | |
| 428 | − return 0; | |
| 429 | −} | |
| 430 | − | |
| 431 | −static int mt9t001_set_selection(struct v4l2_subdev *subdev, | |
| 432 | − struct v4l2_subdev_state *sd_state, | |
| 433 | − struct v4l2_subdev_selection *sel) | |
| 434 | −{ | |
| 435 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 436 | − struct v4l2_mbus_framefmt *__format; | |
| 437 | − struct v4l2_rect *__crop; | |
| 438 | − struct v4l2_rect rect; | |
| 439 | − | |
| 440 | − if (sel->target != V4L2_SEL_TGT_CROP) | |
| 441 | − return -EINVAL; | |
| 442 | − | |
| 443 | − /* Clamp the crop rectangle boundaries and align them to a multiple of 2 | |
| 444 | − * pixels. | |
| 445 | − */ | |
| 446 | − rect.left = clamp(ALIGN(sel->r.left, 2), | |
| 447 | − MT9T001_COLUMN_START_MIN, | |
| 448 | − MT9T001_COLUMN_START_MAX); | |
| 449 | − rect.top = clamp(ALIGN(sel->r.top, 2), | |
| 450 | − MT9T001_ROW_START_MIN, | |
| 451 | − MT9T001_ROW_START_MAX); | |
| 452 | − rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), | |
| 453 | − MT9T001_WINDOW_WIDTH_MIN + 1, | |
| 454 | − MT9T001_WINDOW_WIDTH_MAX + 1); | |
| 455 | − rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), | |
| 456 | − MT9T001_WINDOW_HEIGHT_MIN + 1, | |
| 457 | − MT9T001_WINDOW_HEIGHT_MAX + 1); | |
| 458 | − | |
| 459 | − rect.width = min_t(unsigned int, rect.width, | |
| 460 | − MT9T001_PIXEL_ARRAY_WIDTH - rect.left); | |
| 461 | − rect.height = min_t(unsigned int, rect.height, | |
| 462 | − MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); | |
| 463 | − | |
| 464 | − __crop = __mt9t001_get_pad_crop(mt9t001, sd_state, sel->pad, | |
| 465 | − sel->which); | |
| 466 | − | |
| 467 | − if (rect.width != __crop->width || rect.height != __crop->height) { | |
| 468 | − /* Reset the output image size if the crop rectangle size has | |
| 469 | − * been modified. | |
| 470 | − */ | |
| 471 | − __format = __mt9t001_get_pad_format(mt9t001, sd_state, | |
| 472 | − sel->pad, | |
| 473 | − sel->which); | |
| 474 | − __format->width = rect.width; | |
| 475 | − __format->height = rect.height; | |
| 476 | − } | |
| 477 | − | |
| 478 | − *__crop = rect; | |
| 479 | − sel->r = rect; | |
| 480 | − | |
| 481 | − return 0; | |
| 482 | −} | |
| 483 | − | |
| 484 | −/* ----------------------------------------------------------------------------- | |
| 485 | − * V4L2 subdev control operations | |
| 486 | − */ | |
| 487 | − | |
| 488 | −#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) | |
| 489 | −#define V4L2_CID_BLACK_LEVEL_AUTO (V4L2_CID_USER_BASE | 0x1002) | |
| 490 | −#define V4L2_CID_BLACK_LEVEL_OFFSET (V4L2_CID_USER_BASE | 0x1003) | |
| 491 | −#define V4L2_CID_BLACK_LEVEL_CALIBRATE (V4L2_CID_USER_BASE | 0x1004) | |
| 492 | − | |
| 493 | −#define V4L2_CID_GAIN_RED (V4L2_CTRL_CLASS_CAMERA | 0x1001) | |
| 494 | −#define V4L2_CID_GAIN_GREEN_RED (V4L2_CTRL_CLASS_CAMERA | 0x1002) | |
| 495 | −#define V4L2_CID_GAIN_GREEN_BLUE (V4L2_CTRL_CLASS_CAMERA | 0x1003) | |
| 496 | −#define V4L2_CID_GAIN_BLUE (V4L2_CTRL_CLASS_CAMERA | 0x1004) | |
| 497 | − | |
| 498 | −static u16 mt9t001_gain_value(s32 *gain) | |
| 499 | −{ | |
| 500 | − /* Gain is controlled by 2 analog stages and a digital stage. Valid | |
| 501 | − * values for the 3 stages are | |
| 502 | − * | |
| 503 | − * Stage Min Max Step | |
| 504 | − * ------------------------------------------ | |
| 505 | − * First analog stage x1 x2 1 | |
| 506 | − * Second analog stage x1 x4 0.125 | |
| 507 | − * Digital stage x1 x16 0.125 | |
| 508 | − * | |
| 509 | − * To minimize noise, the gain stages should be used in the second | |
| 510 | − * analog stage, first analog stage, digital stage order. Gain from a | |
| 511 | − * previous stage should be pushed to its maximum value before the next | |
| 512 | − * stage is used. | |
| 513 | − */ | |
| 514 | − if (*gain <= 32) | |
| 515 | − return *gain; | |
| 516 | − | |
| 517 | − if (*gain <= 64) { | |
| 518 | − *gain &= ~1; | |
| 519 | − return (1 << 6) | (*gain >> 1); | |
| 520 | − } | |
| 521 | − | |
| 522 | − *gain &= ~7; | |
| 523 | − return ((*gain - 64) << 5) | (1 << 6) | 32; | |
| 524 | −} | |
| 525 | − | |
| 526 | −static int mt9t001_ctrl_freeze(struct mt9t001 *mt9t001, bool freeze) | |
| 527 | −{ | |
| 528 | − return mt9t001_set_output_control(mt9t001, | |
| 529 | − freeze ? 0 : MT9T001_OUTPUT_CONTROL_SYNC, | |
| 530 | − freeze ? MT9T001_OUTPUT_CONTROL_SYNC : 0); | |
| 531 | −} | |
| 532 | − | |
| 533 | −static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 534 | −{ | |
| 535 | − static const u8 gains[4] = { | |
| 536 | − MT9T001_RED_GAIN, MT9T001_GREEN1_GAIN, | |
| 537 | − MT9T001_GREEN2_GAIN, MT9T001_BLUE_GAIN | |
| 538 | − }; | |
| 539 | − | |
| 540 | − struct mt9t001 *mt9t001 = | |
| 541 | − container_of(ctrl->handler, struct mt9t001, ctrls); | |
| 542 | − struct i2c_client *client = v4l2_get_subdevdata(&mt9t001->subdev); | |
| 543 | − unsigned int count; | |
| 544 | − unsigned int i; | |
| 545 | − u16 value; | |
| 546 | − int ret; | |
| 547 | − | |
| 548 | − switch (ctrl->id) { | |
| 549 | − case V4L2_CID_GAIN_RED: | |
| 550 | − case V4L2_CID_GAIN_GREEN_RED: | |
| 551 | − case V4L2_CID_GAIN_GREEN_BLUE: | |
| 552 | − case V4L2_CID_GAIN_BLUE: | |
| 553 | − | |
| 554 | − /* Disable control updates if more than one control has changed | |
| 555 | − * in the cluster. | |
| 556 | − */ | |
| 557 | − for (i = 0, count = 0; i < 4; ++i) { | |
| 558 | − struct v4l2_ctrl *gain = mt9t001->gains[i]; | |
| 559 | − | |
| 560 | − if (gain->val != gain->cur.val) | |
| 561 | − count++; | |
| 562 | − } | |
| 563 | − | |
| 564 | − if (count > 1) { | |
| 565 | − ret = mt9t001_ctrl_freeze(mt9t001, true); | |
| 566 | − if (ret < 0) | |
| 567 | − return ret; | |
| 568 | − } | |
| 569 | − | |
| 570 | − /* Update the gain controls. */ | |
| 571 | − for (i = 0; i < 4; ++i) { | |
| 572 | − struct v4l2_ctrl *gain = mt9t001->gains[i]; | |
| 573 | − | |
| 574 | − if (gain->val == gain->cur.val) | |
| 575 | − continue; | |
| 576 | − | |
| 577 | − value = mt9t001_gain_value(&gain->val); | |
| 578 | − ret = mt9t001_write(client, gains[i], value); | |
| 579 | − if (ret < 0) { | |
| 580 | − mt9t001_ctrl_freeze(mt9t001, false); | |
| 581 | − return ret; | |
| 582 | − } | |
| 583 | − } | |
| 584 | − | |
| 585 | − /* Enable control updates. */ | |
| 586 | − if (count > 1) { | |
| 587 | − ret = mt9t001_ctrl_freeze(mt9t001, false); | |
| 588 | − if (ret < 0) | |
| 589 | − return ret; | |
| 590 | − } | |
| 591 | − | |
| 592 | − break; | |
| 593 | − | |
| 594 | − case V4L2_CID_EXPOSURE: | |
| 595 | − ret = mt9t001_write(client, MT9T001_SHUTTER_WIDTH_LOW, | |
| 596 | − ctrl->val & 0xffff); | |
| 597 | − if (ret < 0) | |
| 598 | − return ret; | |
| 599 | − | |
| 600 | − return mt9t001_write(client, MT9T001_SHUTTER_WIDTH_HIGH, | |
| 601 | − ctrl->val >> 16); | |
| 602 | − | |
| 603 | − case V4L2_CID_TEST_PATTERN: | |
| 604 | − return mt9t001_set_output_control(mt9t001, | |
| 605 | − ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA, | |
| 606 | − ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0); | |
| 607 | − | |
| 608 | − case V4L2_CID_TEST_PATTERN_COLOR: | |
| 609 | − return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2); | |
| 610 | − | |
| 611 | − case V4L2_CID_BLACK_LEVEL_AUTO: | |
| 612 | − value = ctrl->val ? 0 : MT9T001_BLACK_LEVEL_OVERRIDE; | |
| 613 | − ret = mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION, | |
| 614 | − value); | |
| 615 | − if (ret < 0) | |
| 616 | − return ret; | |
| 617 | − | |
| 618 | − mt9t001->black_level = value; | |
| 619 | − break; | |
| 620 | − | |
| 621 | − case V4L2_CID_BLACK_LEVEL_OFFSET: | |
| 622 | − ret = mt9t001_write(client, MT9T001_GREEN1_OFFSET, ctrl->val); | |
| 623 | − if (ret < 0) | |
| 624 | − return ret; | |
| 625 | − | |
| 626 | − ret = mt9t001_write(client, MT9T001_GREEN2_OFFSET, ctrl->val); | |
| 627 | − if (ret < 0) | |
| 628 | − return ret; | |
| 629 | − | |
| 630 | − ret = mt9t001_write(client, MT9T001_RED_OFFSET, ctrl->val); | |
| 631 | − if (ret < 0) | |
| 632 | − return ret; | |
| 633 | − | |
| 634 | − return mt9t001_write(client, MT9T001_BLUE_OFFSET, ctrl->val); | |
| 635 | − | |
| 636 | − case V4L2_CID_BLACK_LEVEL_CALIBRATE: | |
| 637 | − return mt9t001_write(client, MT9T001_BLACK_LEVEL_CALIBRATION, | |
| 638 | − MT9T001_BLACK_LEVEL_RECALCULATE | | |
| 639 | − mt9t001->black_level); | |
| 640 | − } | |
| 641 | − | |
| 642 | − return 0; | |
| 643 | −} | |
| 644 | − | |
| 645 | −static const struct v4l2_ctrl_ops mt9t001_ctrl_ops = { | |
| 646 | − .s_ctrl = mt9t001_s_ctrl, | |
| 647 | −}; | |
| 648 | − | |
| 649 | −static const char * const mt9t001_test_pattern_menu[] = { | |
| 650 | − "Disabled", | |
| 651 | − "Enabled", | |
| 652 | −}; | |
| 653 | − | |
| 654 | −static const struct v4l2_ctrl_config mt9t001_ctrls[] = { | |
| 655 | − { | |
| 656 | − .ops = &mt9t001_ctrl_ops, | |
| 657 | − .id = V4L2_CID_TEST_PATTERN_COLOR, | |
| 658 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 659 | − .name = "Test Pattern Color", | |
| 660 | − .min = 0, | |
| 661 | − .max = 1023, | |
| 662 | − .step = 1, | |
| 663 | − .def = 0, | |
| 664 | − .flags = 0, | |
| 665 | − }, { | |
| 666 | − .ops = &mt9t001_ctrl_ops, | |
| 667 | − .id = V4L2_CID_BLACK_LEVEL_AUTO, | |
| 668 | − .type = V4L2_CTRL_TYPE_BOOLEAN, | |
| 669 | − .name = "Black Level, Auto", | |
| 670 | − .min = 0, | |
| 671 | − .max = 1, | |
| 672 | − .step = 1, | |
| 673 | − .def = 1, | |
| 674 | − .flags = 0, | |
| 675 | − }, { | |
| 676 | − .ops = &mt9t001_ctrl_ops, | |
| 677 | − .id = V4L2_CID_BLACK_LEVEL_OFFSET, | |
| 678 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 679 | − .name = "Black Level, Offset", | |
| 680 | − .min = -256, | |
| 681 | − .max = 255, | |
| 682 | − .step = 1, | |
| 683 | − .def = 32, | |
| 684 | − .flags = 0, | |
| 685 | − }, { | |
| 686 | − .ops = &mt9t001_ctrl_ops, | |
| 687 | − .id = V4L2_CID_BLACK_LEVEL_CALIBRATE, | |
| 688 | − .type = V4L2_CTRL_TYPE_BUTTON, | |
| 689 | − .name = "Black Level, Calibrate", | |
| 690 | − .min = 0, | |
| 691 | − .max = 0, | |
| 692 | − .step = 0, | |
| 693 | − .def = 0, | |
| 694 | − .flags = V4L2_CTRL_FLAG_WRITE_ONLY, | |
| 695 | − }, | |
| 696 | −}; | |
| 697 | − | |
| 698 | −static const struct v4l2_ctrl_config mt9t001_gains[] = { | |
| 699 | − { | |
| 700 | − .ops = &mt9t001_ctrl_ops, | |
| 701 | − .id = V4L2_CID_GAIN_RED, | |
| 702 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 703 | − .name = "Gain, Red", | |
| 704 | − .min = MT9T001_GLOBAL_GAIN_MIN, | |
| 705 | − .max = MT9T001_GLOBAL_GAIN_MAX, | |
| 706 | − .step = 1, | |
| 707 | − .def = MT9T001_GLOBAL_GAIN_MIN, | |
| 708 | − .flags = 0, | |
| 709 | − }, { | |
| 710 | − .ops = &mt9t001_ctrl_ops, | |
| 711 | − .id = V4L2_CID_GAIN_GREEN_RED, | |
| 712 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 713 | − .name = "Gain, Green (R)", | |
| 714 | − .min = MT9T001_GLOBAL_GAIN_MIN, | |
| 715 | − .max = MT9T001_GLOBAL_GAIN_MAX, | |
| 716 | − .step = 1, | |
| 717 | − .def = MT9T001_GLOBAL_GAIN_MIN, | |
| 718 | − .flags = 0, | |
| 719 | − }, { | |
| 720 | − .ops = &mt9t001_ctrl_ops, | |
| 721 | − .id = V4L2_CID_GAIN_GREEN_BLUE, | |
| 722 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 723 | − .name = "Gain, Green (B)", | |
| 724 | − .min = MT9T001_GLOBAL_GAIN_MIN, | |
| 725 | − .max = MT9T001_GLOBAL_GAIN_MAX, | |
| 726 | − .step = 1, | |
| 727 | − .def = MT9T001_GLOBAL_GAIN_MIN, | |
| 728 | − .flags = 0, | |
| 729 | − }, { | |
| 730 | − .ops = &mt9t001_ctrl_ops, | |
| 731 | − .id = V4L2_CID_GAIN_BLUE, | |
| 732 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 733 | − .name = "Gain, Blue", | |
| 734 | − .min = MT9T001_GLOBAL_GAIN_MIN, | |
| 735 | − .max = MT9T001_GLOBAL_GAIN_MAX, | |
| 736 | − .step = 1, | |
| 737 | − .def = MT9T001_GLOBAL_GAIN_MIN, | |
| 738 | − .flags = 0, | |
| 739 | − }, | |
| 740 | −}; | |
| 741 | − | |
| 742 | −/* ----------------------------------------------------------------------------- | |
| 743 | − * V4L2 subdev core operations | |
| 744 | − */ | |
| 745 | − | |
| 746 | −static int mt9t001_set_power(struct v4l2_subdev *subdev, int on) | |
| 747 | −{ | |
| 748 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 749 | − int ret = 0; | |
| 750 | − | |
| 751 | − mutex_lock(&mt9t001->power_lock); | |
| 752 | − | |
| 753 | − /* If the power count is modified from 0 to != 0 or from != 0 to 0, | |
| 754 | − * update the power state. | |
| 755 | − */ | |
| 756 | − if (mt9t001->power_count == !on) { | |
| 757 | − ret = __mt9t001_set_power(mt9t001, !!on); | |
| 758 | − if (ret < 0) | |
| 759 | − goto out; | |
| 760 | − } | |
| 761 | − | |
| 762 | − /* Update the power count. */ | |
| 763 | − mt9t001->power_count += on ? 1 : -1; | |
| 764 | − WARN_ON(mt9t001->power_count < 0); | |
| 765 | − | |
| 766 | −out: | |
| 767 | − mutex_unlock(&mt9t001->power_lock); | |
| 768 | − return ret; | |
| 769 | −} | |
| 770 | − | |
| 771 | −/* ----------------------------------------------------------------------------- | |
| 772 | − * V4L2 subdev internal operations | |
| 773 | − */ | |
| 774 | − | |
| 775 | −static int mt9t001_registered(struct v4l2_subdev *subdev) | |
| 776 | −{ | |
| 777 | − struct i2c_client *client = v4l2_get_subdevdata(subdev); | |
| 778 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 779 | − s32 data; | |
| 780 | − int ret; | |
| 781 | − | |
| 782 | − ret = mt9t001_power_on(mt9t001); | |
| 783 | − if (ret < 0) { | |
| 784 | − dev_err(&client->dev, "MT9T001 power up failed\n"); | |
| 785 | − return ret; | |
| 786 | − } | |
| 787 | − | |
| 788 | − /* Read out the chip version register */ | |
| 789 | − data = mt9t001_read(client, MT9T001_CHIP_VERSION); | |
| 790 | − mt9t001_power_off(mt9t001); | |
| 791 | − | |
| 792 | − if (data != MT9T001_CHIP_ID) { | |
| 793 | − dev_err(&client->dev, | |
| 794 | − "MT9T001 not detected, wrong version 0x%04x\n", data); | |
| 795 | − return -ENODEV; | |
| 796 | − } | |
| 797 | − | |
| 798 | − dev_info(&client->dev, "MT9T001 detected at address 0x%02x\n", | |
| 799 | − client->addr); | |
| 800 | − | |
| 801 | − return 0; | |
| 802 | −} | |
| 803 | − | |
| 804 | −static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | |
| 805 | −{ | |
| 806 | − struct v4l2_mbus_framefmt *format; | |
| 807 | − struct v4l2_rect *crop; | |
| 808 | − | |
| 809 | − crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0); | |
| 810 | − crop->left = MT9T001_COLUMN_START_DEF; | |
| 811 | − crop->top = MT9T001_ROW_START_DEF; | |
| 812 | − crop->width = MT9T001_WINDOW_WIDTH_DEF + 1; | |
| 813 | − crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1; | |
| 814 | − | |
| 815 | − format = v4l2_subdev_get_try_format(subdev, fh->state, 0); | |
| 816 | − format->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 817 | − format->width = MT9T001_WINDOW_WIDTH_DEF + 1; | |
| 818 | − format->height = MT9T001_WINDOW_HEIGHT_DEF + 1; | |
| 819 | − format->field = V4L2_FIELD_NONE; | |
| 820 | − format->colorspace = V4L2_COLORSPACE_SRGB; | |
| 821 | − | |
| 822 | − return mt9t001_set_power(subdev, 1); | |
| 823 | −} | |
| 824 | − | |
| 825 | −static int mt9t001_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | |
| 826 | −{ | |
| 827 | − return mt9t001_set_power(subdev, 0); | |
| 828 | −} | |
| 829 | − | |
| 830 | −static const struct v4l2_subdev_core_ops mt9t001_subdev_core_ops = { | |
| 831 | − .s_power = mt9t001_set_power, | |
| 832 | −}; | |
| 833 | − | |
| 834 | −static const struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = { | |
| 835 | − .s_stream = mt9t001_s_stream, | |
| 836 | −}; | |
| 837 | − | |
| 838 | −static const struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = { | |
| 839 | − .enum_mbus_code = mt9t001_enum_mbus_code, | |
| 840 | − .enum_frame_size = mt9t001_enum_frame_size, | |
| 841 | − .get_fmt = mt9t001_get_format, | |
| 842 | − .set_fmt = mt9t001_set_format, | |
| 843 | − .get_selection = mt9t001_get_selection, | |
| 844 | − .set_selection = mt9t001_set_selection, | |
| 845 | −}; | |
| 846 | − | |
| 847 | −static const struct v4l2_subdev_ops mt9t001_subdev_ops = { | |
| 848 | − .core = &mt9t001_subdev_core_ops, | |
| 849 | − .video = &mt9t001_subdev_video_ops, | |
| 850 | − .pad = &mt9t001_subdev_pad_ops, | |
| 851 | −}; | |
| 852 | − | |
| 853 | −static const struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = { | |
| 854 | − .registered = mt9t001_registered, | |
| 855 | − .open = mt9t001_open, | |
| 856 | − .close = mt9t001_close, | |
| 857 | −}; | |
| 858 | − | |
| 859 | −static int mt9t001_probe(struct i2c_client *client) | |
| 860 | −{ | |
| 861 | − struct mt9t001_platform_data *pdata = client->dev.platform_data; | |
| 862 | − struct mt9t001 *mt9t001; | |
| 863 | − unsigned int i; | |
| 864 | − int ret; | |
| 865 | − | |
| 866 | − if (pdata == NULL) { | |
| 867 | − dev_err(&client->dev, "No platform data\n"); | |
| 868 | − return -EINVAL; | |
| 869 | − } | |
| 870 | − | |
| 871 | − if (!i2c_check_functionality(client->adapter, | |
| 872 | − I2C_FUNC_SMBUS_WORD_DATA)) { | |
| 873 | − dev_warn(&client->adapter->dev, | |
| 874 | − "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | |
| 875 | − return -EIO; | |
| 876 | − } | |
| 877 | − | |
| 878 | − mt9t001 = devm_kzalloc(&client->dev, sizeof(*mt9t001), GFP_KERNEL); | |
| 879 | − if (!mt9t001) | |
| 880 | − return -ENOMEM; | |
| 881 | − | |
| 882 | − mutex_init(&mt9t001->power_lock); | |
| 883 | − mt9t001->output_control = MT9T001_OUTPUT_CONTROL_DEF; | |
| 884 | − | |
| 885 | − mt9t001->regulators[0].supply = "vdd"; | |
| 886 | − mt9t001->regulators[1].supply = "vaa"; | |
| 887 | − | |
| 888 | − ret = devm_regulator_bulk_get(&client->dev, 2, mt9t001->regulators); | |
| 889 | − if (ret < 0) { | |
| 890 | − dev_err(&client->dev, "Unable to get regulators\n"); | |
| 891 | − return ret; | |
| 892 | − } | |
| 893 | − | |
| 894 | − mt9t001->clk = devm_clk_get(&client->dev, NULL); | |
| 895 | − if (IS_ERR(mt9t001->clk)) { | |
| 896 | − dev_err(&client->dev, "Unable to get clock\n"); | |
| 897 | − return PTR_ERR(mt9t001->clk); | |
| 898 | − } | |
| 899 | − | |
| 900 | − v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) + | |
| 901 | − ARRAY_SIZE(mt9t001_gains) + 4); | |
| 902 | − | |
| 903 | − v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, | |
| 904 | − V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN, | |
| 905 | − MT9T001_SHUTTER_WIDTH_MAX, 1, | |
| 906 | − MT9T001_SHUTTER_WIDTH_DEF); | |
| 907 | − v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, | |
| 908 | − V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1); | |
| 909 | − v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, | |
| 910 | − V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk, | |
| 911 | − 1, pdata->ext_clk); | |
| 912 | − v4l2_ctrl_new_std_menu_items(&mt9t001->ctrls, &mt9t001_ctrl_ops, | |
| 913 | − V4L2_CID_TEST_PATTERN, | |
| 914 | − ARRAY_SIZE(mt9t001_test_pattern_menu) - 1, 0, | |
| 915 | − 0, mt9t001_test_pattern_menu); | |
| 916 | − | |
| 917 | − for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i) | |
| 918 | − v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL); | |
| 919 | − | |
| 920 | − for (i = 0; i < ARRAY_SIZE(mt9t001_gains); ++i) | |
| 921 | − mt9t001->gains[i] = v4l2_ctrl_new_custom(&mt9t001->ctrls, | |
| 922 | − &mt9t001_gains[i], NULL); | |
| 923 | − | |
| 924 | − v4l2_ctrl_cluster(ARRAY_SIZE(mt9t001_gains), mt9t001->gains); | |
| 925 | − | |
| 926 | − mt9t001->subdev.ctrl_handler = &mt9t001->ctrls; | |
| 927 | − | |
| 928 | − if (mt9t001->ctrls.error) { | |
| 929 | − printk(KERN_INFO "%s: control initialization error %d\n", | |
| 930 | − __func__, mt9t001->ctrls.error); | |
| 931 | − ret = -EINVAL; | |
| 932 | − goto done; | |
| 933 | − } | |
| 934 | − | |
| 935 | − mt9t001->crop.left = MT9T001_COLUMN_START_DEF; | |
| 936 | − mt9t001->crop.top = MT9T001_ROW_START_DEF; | |
| 937 | − mt9t001->crop.width = MT9T001_WINDOW_WIDTH_DEF + 1; | |
| 938 | − mt9t001->crop.height = MT9T001_WINDOW_HEIGHT_DEF + 1; | |
| 939 | − | |
| 940 | − mt9t001->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 941 | − mt9t001->format.width = MT9T001_WINDOW_WIDTH_DEF + 1; | |
| 942 | − mt9t001->format.height = MT9T001_WINDOW_HEIGHT_DEF + 1; | |
| 943 | − mt9t001->format.field = V4L2_FIELD_NONE; | |
| 944 | − mt9t001->format.colorspace = V4L2_COLORSPACE_SRGB; | |
| 945 | − | |
| 946 | − v4l2_i2c_subdev_init(&mt9t001->subdev, client, &mt9t001_subdev_ops); | |
| 947 | − mt9t001->subdev.internal_ops = &mt9t001_subdev_internal_ops; | |
| 948 | − mt9t001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 949 | − | |
| 950 | − mt9t001->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 951 | − mt9t001->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 952 | − ret = media_entity_pads_init(&mt9t001->subdev.entity, 1, &mt9t001->pad); | |
| 953 | − | |
| 954 | −done: | |
| 955 | − if (ret < 0) { | |
| 956 | − v4l2_ctrl_handler_free(&mt9t001->ctrls); | |
| 957 | − media_entity_cleanup(&mt9t001->subdev.entity); | |
| 958 | − } | |
| 959 | − | |
| 960 | − return ret; | |
| 961 | −} | |
| 962 | − | |
| 963 | −static void mt9t001_remove(struct i2c_client *client) | |
| 964 | −{ | |
| 965 | − struct v4l2_subdev *subdev = i2c_get_clientdata(client); | |
| 966 | − struct mt9t001 *mt9t001 = to_mt9t001(subdev); | |
| 967 | − | |
| 968 | − v4l2_ctrl_handler_free(&mt9t001->ctrls); | |
| 969 | − v4l2_device_unregister_subdev(subdev); | |
| 970 | − media_entity_cleanup(&subdev->entity); | |
| 971 | −} | |
| 972 | − | |
| 973 | −static const struct i2c_device_id mt9t001_id[] = { | |
| 974 | − { "mt9t001", 0 }, | |
| 975 | − { } | |
| 976 | −}; | |
| 977 | −MODULE_DEVICE_TABLE(i2c, mt9t001_id); | |
| 978 | − | |
| 979 | −static struct i2c_driver mt9t001_driver = { | |
| 980 | − .driver = { | |
| 981 | − .name = "mt9t001", | |
| 982 | − }, | |
| 983 | − .probe_new = mt9t001_probe, | |
| 984 | − .remove = mt9t001_remove, | |
| 985 | − .id_table = mt9t001_id, | |
| 986 | −}; | |
| 987 | − | |
| 988 | −module_i2c_driver(mt9t001_driver); | |
| 989 | − | |
| 990 | −MODULE_DESCRIPTION("Aptina (Micron) MT9T001 Camera driver"); | |
| 991 | −MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | |
| 992 | −MODULE_LICENSE("GPL"); | |
| @@ -1,821 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP | |
| 4 | − * | |
| 5 | − * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd. | |
| 6 | − * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com> | |
| 7 | − * | |
| 8 | − * Initial register configuration based on a driver authored by | |
| 9 | − * HeungJun Kim <riverful.kim@samsung.com>. | |
| 10 | − */ | |
| 11 | − | |
| 12 | −#include <linux/delay.h> | |
| 13 | −#include <linux/gpio/consumer.h> | |
| 14 | −#include <linux/i2c.h> | |
| 15 | −#include <linux/slab.h> | |
| 16 | −#include <linux/regulator/consumer.h> | |
| 17 | −#include <media/i2c/noon010pc30.h> | |
| 18 | −#include <linux/videodev2.h> | |
| 19 | −#include <linux/module.h> | |
| 20 | −#include <media/v4l2-ctrls.h> | |
| 21 | −#include <media/v4l2-device.h> | |
| 22 | −#include <media/v4l2-mediabus.h> | |
| 23 | −#include <media/v4l2-subdev.h> | |
| 24 | − | |
| 25 | −static int debug; | |
| 26 | −module_param(debug, int, 0644); | |
| 27 | −MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable."); | |
| 28 | − | |
| 29 | −#define MODULE_NAME "NOON010PC30" | |
| 30 | − | |
| 31 | −/* | |
| 32 | − * Register offsets within a page | |
| 33 | − * b15..b8 - page id, b7..b0 - register address | |
| 34 | − */ | |
| 35 | −#define POWER_CTRL_REG 0x0001 | |
| 36 | −#define PAGEMODE_REG 0x03 | |
| 37 | −#define DEVICE_ID_REG 0x0004 | |
| 38 | −#define NOON010PC30_ID 0x86 | |
| 39 | −#define VDO_CTL_REG(n) (0x0010 + (n)) | |
| 40 | −#define SYNC_CTL_REG 0x0012 | |
| 41 | −/* Window size and position */ | |
| 42 | −#define WIN_ROWH_REG 0x0013 | |
| 43 | −#define WIN_ROWL_REG 0x0014 | |
| 44 | −#define WIN_COLH_REG 0x0015 | |
| 45 | −#define WIN_COLL_REG 0x0016 | |
| 46 | −#define WIN_HEIGHTH_REG 0x0017 | |
| 47 | −#define WIN_HEIGHTL_REG 0x0018 | |
| 48 | −#define WIN_WIDTHH_REG 0x0019 | |
| 49 | −#define WIN_WIDTHL_REG 0x001A | |
| 50 | −#define HBLANKH_REG 0x001B | |
| 51 | −#define HBLANKL_REG 0x001C | |
| 52 | −#define VSYNCH_REG 0x001D | |
| 53 | −#define VSYNCL_REG 0x001E | |
| 54 | −/* VSYNC control */ | |
| 55 | −#define VS_CTL_REG(n) (0x00A1 + (n)) | |
| 56 | −/* page 1 */ | |
| 57 | −#define ISP_CTL_REG(n) (0x0110 + (n)) | |
| 58 | −#define YOFS_REG 0x0119 | |
| 59 | −#define DARK_YOFS_REG 0x011A | |
| 60 | −#define SAT_CTL_REG 0x0120 | |
| 61 | −#define BSAT_REG 0x0121 | |
| 62 | −#define RSAT_REG 0x0122 | |
| 63 | −/* Color correction */ | |
| 64 | −#define CMC_CTL_REG 0x0130 | |
| 65 | −#define CMC_OFSGH_REG 0x0133 | |
| 66 | −#define CMC_OFSGL_REG 0x0135 | |
| 67 | −#define CMC_SIGN_REG 0x0136 | |
| 68 | −#define CMC_GOFS_REG 0x0137 | |
| 69 | −#define CMC_COEF_REG(n) (0x0138 + (n)) | |
| 70 | −#define CMC_OFS_REG(n) (0x0141 + (n)) | |
| 71 | −/* Gamma correction */ | |
| 72 | −#define GMA_CTL_REG 0x0160 | |
| 73 | −#define GMA_COEF_REG(n) (0x0161 + (n)) | |
| 74 | −/* Lens Shading */ | |
| 75 | −#define LENS_CTRL_REG 0x01D0 | |
| 76 | −#define LENS_XCEN_REG 0x01D1 | |
| 77 | −#define LENS_YCEN_REG 0x01D2 | |
| 78 | −#define LENS_RC_REG 0x01D3 | |
| 79 | −#define LENS_GC_REG 0x01D4 | |
| 80 | −#define LENS_BC_REG 0x01D5 | |
| 81 | −#define L_AGON_REG 0x01D6 | |
| 82 | −#define L_AGOFF_REG 0x01D7 | |
| 83 | −/* Page 3 - Auto Exposure */ | |
| 84 | −#define AE_CTL_REG(n) (0x0310 + (n)) | |
| 85 | −#define AE_CTL9_REG 0x032C | |
| 86 | −#define AE_CTL10_REG 0x032D | |
| 87 | −#define AE_YLVL_REG 0x031C | |
| 88 | −#define AE_YTH_REG(n) (0x031D + (n)) | |
| 89 | −#define AE_WGT_REG 0x0326 | |
| 90 | −#define EXP_TIMEH_REG 0x0333 | |
| 91 | −#define EXP_TIMEM_REG 0x0334 | |
| 92 | −#define EXP_TIMEL_REG 0x0335 | |
| 93 | −#define EXP_MMINH_REG 0x0336 | |
| 94 | −#define EXP_MMINL_REG 0x0337 | |
| 95 | −#define EXP_MMAXH_REG 0x0338 | |
| 96 | −#define EXP_MMAXM_REG 0x0339 | |
| 97 | −#define EXP_MMAXL_REG 0x033A | |
| 98 | −/* Page 4 - Auto White Balance */ | |
| 99 | −#define AWB_CTL_REG(n) (0x0410 + (n)) | |
| 100 | −#define AWB_ENABE 0x80 | |
| 101 | −#define AWB_WGHT_REG 0x0419 | |
| 102 | −#define BGAIN_PAR_REG(n) (0x044F + (n)) | |
| 103 | −/* Manual white balance, when AWB_CTL2[0]=1 */ | |
| 104 | −#define MWB_RGAIN_REG 0x0466 | |
| 105 | −#define MWB_BGAIN_REG 0x0467 | |
| 106 | − | |
| 107 | −/* The token to mark an array end */ | |
| 108 | −#define REG_TERM 0xFFFF | |
| 109 | − | |
| 110 | −struct noon010_format { | |
| 111 | − u32 code; | |
| 112 | − enum v4l2_colorspace colorspace; | |
| 113 | − u16 ispctl1_reg; | |
| 114 | −}; | |
| 115 | − | |
| 116 | −struct noon010_frmsize { | |
| 117 | − u16 width; | |
| 118 | − u16 height; | |
| 119 | − int vid_ctl1; | |
| 120 | −}; | |
| 121 | − | |
| 122 | −static const char * const noon010_supply_name[] = { | |
| 123 | − "vdd_core", "vddio", "vdda" | |
| 124 | −}; | |
| 125 | − | |
| 126 | −#define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name) | |
| 127 | − | |
| 128 | −struct noon010_info { | |
| 129 | − struct v4l2_subdev sd; | |
| 130 | − struct media_pad pad; | |
| 131 | − struct v4l2_ctrl_handler hdl; | |
| 132 | − struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES]; | |
| 133 | − struct gpio_desc *reset; | |
| 134 | − struct gpio_desc *stby; | |
| 135 | − | |
| 136 | − /* Protects the struct members below */ | |
| 137 | − struct mutex lock; | |
| 138 | − | |
| 139 | − const struct noon010_format *curr_fmt; | |
| 140 | − const struct noon010_frmsize *curr_win; | |
| 141 | − unsigned int apply_new_cfg:1; | |
| 142 | − unsigned int streaming:1; | |
| 143 | − unsigned int hflip:1; | |
| 144 | − unsigned int vflip:1; | |
| 145 | − unsigned int power:1; | |
| 146 | − u8 i2c_reg_page; | |
| 147 | −}; | |
| 148 | − | |
| 149 | −struct i2c_regval { | |
| 150 | − u16 addr; | |
| 151 | − u16 val; | |
| 152 | −}; | |
| 153 | − | |
| 154 | −/* Supported resolutions. */ | |
| 155 | −static const struct noon010_frmsize noon010_sizes[] = { | |
| 156 | − { | |
| 157 | − .width = 352, | |
| 158 | − .height = 288, | |
| 159 | − .vid_ctl1 = 0, | |
| 160 | − }, { | |
| 161 | − .width = 176, | |
| 162 | − .height = 144, | |
| 163 | − .vid_ctl1 = 0x10, | |
| 164 | − }, { | |
| 165 | − .width = 88, | |
| 166 | − .height = 72, | |
| 167 | − .vid_ctl1 = 0x20, | |
| 168 | − }, | |
| 169 | −}; | |
| 170 | − | |
| 171 | −/* Supported pixel formats. */ | |
| 172 | −static const struct noon010_format noon010_formats[] = { | |
| 173 | − { | |
| 174 | − .code = MEDIA_BUS_FMT_YUYV8_2X8, | |
| 175 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 176 | − .ispctl1_reg = 0x03, | |
| 177 | − }, { | |
| 178 | − .code = MEDIA_BUS_FMT_YVYU8_2X8, | |
| 179 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 180 | − .ispctl1_reg = 0x02, | |
| 181 | − }, { | |
| 182 | − .code = MEDIA_BUS_FMT_VYUY8_2X8, | |
| 183 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 184 | − .ispctl1_reg = 0, | |
| 185 | − }, { | |
| 186 | − .code = MEDIA_BUS_FMT_UYVY8_2X8, | |
| 187 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 188 | − .ispctl1_reg = 0x01, | |
| 189 | − }, { | |
| 190 | − .code = MEDIA_BUS_FMT_RGB565_2X8_BE, | |
| 191 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 192 | − .ispctl1_reg = 0x40, | |
| 193 | − }, | |
| 194 | −}; | |
| 195 | − | |
| 196 | −static const struct i2c_regval noon010_base_regs[] = { | |
| 197 | − { WIN_COLL_REG, 0x06 }, { HBLANKL_REG, 0x7C }, | |
| 198 | − /* Color corection and saturation */ | |
| 199 | − { ISP_CTL_REG(0), 0x30 }, { ISP_CTL_REG(2), 0x30 }, | |
| 200 | − { YOFS_REG, 0x80 }, { DARK_YOFS_REG, 0x04 }, | |
| 201 | − { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 }, | |
| 202 | − { CMC_CTL_REG, 0x0F }, { CMC_OFSGH_REG, 0x3C }, | |
| 203 | − { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x3F }, | |
| 204 | − { CMC_COEF_REG(0), 0x79 }, { CMC_OFS_REG(0), 0x00 }, | |
| 205 | − { CMC_COEF_REG(1), 0x39 }, { CMC_OFS_REG(1), 0x00 }, | |
| 206 | − { CMC_COEF_REG(2), 0x00 }, { CMC_OFS_REG(2), 0x00 }, | |
| 207 | − { CMC_COEF_REG(3), 0x11 }, { CMC_OFS_REG(3), 0x8B }, | |
| 208 | − { CMC_COEF_REG(4), 0x65 }, { CMC_OFS_REG(4), 0x07 }, | |
| 209 | − { CMC_COEF_REG(5), 0x14 }, { CMC_OFS_REG(5), 0x04 }, | |
| 210 | − { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x9C }, | |
| 211 | − { CMC_COEF_REG(7), 0x33 }, { CMC_OFS_REG(7), 0x89 }, | |
| 212 | − { CMC_COEF_REG(8), 0x74 }, { CMC_OFS_REG(8), 0x25 }, | |
| 213 | − /* Automatic white balance */ | |
| 214 | − { AWB_CTL_REG(0), 0x78 }, { AWB_CTL_REG(1), 0x2E }, | |
| 215 | − { AWB_CTL_REG(2), 0x20 }, { AWB_CTL_REG(3), 0x85 }, | |
| 216 | − /* Auto exposure */ | |
| 217 | − { AE_CTL_REG(0), 0xDC }, { AE_CTL_REG(1), 0x81 }, | |
| 218 | − { AE_CTL_REG(2), 0x30 }, { AE_CTL_REG(3), 0xA5 }, | |
| 219 | − { AE_CTL_REG(4), 0x40 }, { AE_CTL_REG(5), 0x51 }, | |
| 220 | − { AE_CTL_REG(6), 0x33 }, { AE_CTL_REG(7), 0x7E }, | |
| 221 | − { AE_CTL9_REG, 0x00 }, { AE_CTL10_REG, 0x02 }, | |
| 222 | − { AE_YLVL_REG, 0x44 }, { AE_YTH_REG(0), 0x34 }, | |
| 223 | − { AE_YTH_REG(1), 0x30 }, { AE_WGT_REG, 0xD5 }, | |
| 224 | − /* Lens shading compensation */ | |
| 225 | − { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 }, | |
| 226 | − { LENS_YCEN_REG, 0x70 }, { LENS_RC_REG, 0x53 }, | |
| 227 | − { LENS_GC_REG, 0x40 }, { LENS_BC_REG, 0x3E }, | |
| 228 | − { REG_TERM, 0 }, | |
| 229 | −}; | |
| 230 | − | |
| 231 | −static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd) | |
| 232 | −{ | |
| 233 | − return container_of(sd, struct noon010_info, sd); | |
| 234 | −} | |
| 235 | − | |
| 236 | −static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | |
| 237 | −{ | |
| 238 | − return &container_of(ctrl->handler, struct noon010_info, hdl)->sd; | |
| 239 | −} | |
| 240 | − | |
| 241 | −static inline int set_i2c_page(struct noon010_info *info, | |
| 242 | − struct i2c_client *client, unsigned int reg) | |
| 243 | −{ | |
| 244 | − u32 page = reg >> 8 & 0xFF; | |
| 245 | − int ret = 0; | |
| 246 | − | |
| 247 | − if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) { | |
| 248 | − ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page); | |
| 249 | − if (!ret) | |
| 250 | − info->i2c_reg_page = page; | |
| 251 | − } | |
| 252 | − return ret; | |
| 253 | −} | |
| 254 | − | |
| 255 | −static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr) | |
| 256 | −{ | |
| 257 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 258 | − struct noon010_info *info = to_noon010(sd); | |
| 259 | − int ret = set_i2c_page(info, client, reg_addr); | |
| 260 | − | |
| 261 | − if (ret) | |
| 262 | − return ret; | |
| 263 | − return i2c_smbus_read_byte_data(client, reg_addr & 0xFF); | |
| 264 | −} | |
| 265 | − | |
| 266 | −static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val) | |
| 267 | −{ | |
| 268 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 269 | − struct noon010_info *info = to_noon010(sd); | |
| 270 | − int ret = set_i2c_page(info, client, reg_addr); | |
| 271 | − | |
| 272 | − if (ret) | |
| 273 | − return ret; | |
| 274 | − return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val); | |
| 275 | −} | |
| 276 | − | |
| 277 | −static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd, | |
| 278 | − const struct i2c_regval *msg) | |
| 279 | −{ | |
| 280 | − while (msg->addr != REG_TERM) { | |
| 281 | − int ret = cam_i2c_write(sd, msg->addr, msg->val); | |
| 282 | − | |
| 283 | − if (ret) | |
| 284 | − return ret; | |
| 285 | − msg++; | |
| 286 | − } | |
| 287 | − return 0; | |
| 288 | −} | |
| 289 | − | |
| 290 | −/* Device reset and sleep mode control */ | |
| 291 | −static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep) | |
| 292 | −{ | |
| 293 | − struct noon010_info *info = to_noon010(sd); | |
| 294 | − u8 reg = sleep ? 0xF1 : 0xF0; | |
| 295 | − int ret = 0; | |
| 296 | − | |
| 297 | − if (reset) { | |
| 298 | − ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02); | |
| 299 | − udelay(20); | |
| 300 | − } | |
| 301 | − if (!ret) { | |
| 302 | − ret = cam_i2c_write(sd, POWER_CTRL_REG, reg); | |
| 303 | − if (reset && !ret) | |
| 304 | − info->i2c_reg_page = -1; | |
| 305 | − } | |
| 306 | − return ret; | |
| 307 | −} | |
| 308 | − | |
| 309 | −/* Automatic white balance control */ | |
| 310 | −static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on) | |
| 311 | −{ | |
| 312 | − int ret; | |
| 313 | − | |
| 314 | − ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F); | |
| 315 | − if (!ret) | |
| 316 | − ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B); | |
| 317 | − return ret; | |
| 318 | −} | |
| 319 | − | |
| 320 | −/* Called with struct noon010_info.lock mutex held */ | |
| 321 | −static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip) | |
| 322 | −{ | |
| 323 | − struct noon010_info *info = to_noon010(sd); | |
| 324 | − int reg, ret; | |
| 325 | − | |
| 326 | − reg = cam_i2c_read(sd, VDO_CTL_REG(1)); | |
| 327 | − if (reg < 0) | |
| 328 | − return reg; | |
| 329 | − | |
| 330 | − reg &= 0x7C; | |
| 331 | − if (hflip) | |
| 332 | − reg |= 0x01; | |
| 333 | − if (vflip) | |
| 334 | − reg |= 0x02; | |
| 335 | − | |
| 336 | − ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80); | |
| 337 | − if (!ret) { | |
| 338 | − info->hflip = hflip; | |
| 339 | − info->vflip = vflip; | |
| 340 | − } | |
| 341 | − return ret; | |
| 342 | −} | |
| 343 | − | |
| 344 | −/* Configure resolution and color format */ | |
| 345 | −static int noon010_set_params(struct v4l2_subdev *sd) | |
| 346 | −{ | |
| 347 | − struct noon010_info *info = to_noon010(sd); | |
| 348 | − | |
| 349 | − int ret = cam_i2c_write(sd, VDO_CTL_REG(0), | |
| 350 | − info->curr_win->vid_ctl1); | |
| 351 | − if (ret) | |
| 352 | − return ret; | |
| 353 | − return cam_i2c_write(sd, ISP_CTL_REG(0), | |
| 354 | − info->curr_fmt->ispctl1_reg); | |
| 355 | −} | |
| 356 | − | |
| 357 | −/* Find nearest matching image pixel size. */ | |
| 358 | −static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf, | |
| 359 | − const struct noon010_frmsize **size) | |
| 360 | −{ | |
| 361 | − unsigned int min_err = ~0; | |
| 362 | − int i = ARRAY_SIZE(noon010_sizes); | |
| 363 | − const struct noon010_frmsize *fsize = &noon010_sizes[0], | |
| 364 | − *match = NULL; | |
| 365 | − | |
| 366 | − while (i--) { | |
| 367 | − int err = abs(fsize->width - mf->width) | |
| 368 | − + abs(fsize->height - mf->height); | |
| 369 | − | |
| 370 | − if (err < min_err) { | |
| 371 | − min_err = err; | |
| 372 | − match = fsize; | |
| 373 | − } | |
| 374 | − fsize++; | |
| 375 | − } | |
| 376 | − if (match) { | |
| 377 | − mf->width = match->width; | |
| 378 | − mf->height = match->height; | |
| 379 | − if (size) | |
| 380 | − *size = match; | |
| 381 | − return 0; | |
| 382 | − } | |
| 383 | − return -EINVAL; | |
| 384 | −} | |
| 385 | − | |
| 386 | −/* Called with info.lock mutex held */ | |
| 387 | −static int power_enable(struct noon010_info *info) | |
| 388 | −{ | |
| 389 | − int ret; | |
| 390 | − | |
| 391 | − if (info->power) { | |
| 392 | − v4l2_info(&info->sd, "%s: sensor is already on\n", __func__); | |
| 393 | − return 0; | |
| 394 | − } | |
| 395 | − | |
| 396 | − /* Assert standby: line should be flagged active low in descriptor */ | |
| 397 | − if (info->stby) | |
| 398 | − gpiod_set_value(info->stby, 1); | |
| 399 | − | |
| 400 | − /* Assert reset: line should be flagged active low in descriptor */ | |
| 401 | − if (info->reset) | |
| 402 | − gpiod_set_value(info->reset, 1); | |
| 403 | − | |
| 404 | − ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply); | |
| 405 | − if (ret) | |
| 406 | − return ret; | |
| 407 | − | |
| 408 | − /* De-assert reset and standby */ | |
| 409 | − if (info->reset) { | |
| 410 | − msleep(50); | |
| 411 | − gpiod_set_value(info->reset, 0); | |
| 412 | − } | |
| 413 | − if (info->stby) { | |
| 414 | − udelay(1000); | |
| 415 | − gpiod_set_value(info->stby, 0); | |
| 416 | − } | |
| 417 | − /* Cycle reset: assert and deassert */ | |
| 418 | − if (info->reset) { | |
| 419 | − udelay(1000); | |
| 420 | − gpiod_set_value(info->reset, 1); | |
| 421 | − msleep(100); | |
| 422 | − gpiod_set_value(info->reset, 0); | |
| 423 | − msleep(20); | |
| 424 | − } | |
| 425 | − info->power = 1; | |
| 426 | − | |
| 427 | − v4l2_dbg(1, debug, &info->sd, "%s: sensor is on\n", __func__); | |
| 428 | − return 0; | |
| 429 | −} | |
| 430 | − | |
| 431 | −/* Called with info.lock mutex held */ | |
| 432 | −static int power_disable(struct noon010_info *info) | |
| 433 | −{ | |
| 434 | − int ret; | |
| 435 | − | |
| 436 | − if (!info->power) { | |
| 437 | − v4l2_info(&info->sd, "%s: sensor is already off\n", __func__); | |
| 438 | − return 0; | |
| 439 | − } | |
| 440 | − | |
| 441 | − ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply); | |
| 442 | − if (ret) | |
| 443 | − return ret; | |
| 444 | − | |
| 445 | − /* Assert standby and reset */ | |
| 446 | − if (info->stby) | |
| 447 | − gpiod_set_value(info->stby, 1); | |
| 448 | − | |
| 449 | − if (info->reset) | |
| 450 | − gpiod_set_value(info->reset, 1); | |
| 451 | − | |
| 452 | − info->power = 0; | |
| 453 | − | |
| 454 | − v4l2_dbg(1, debug, &info->sd, "%s: sensor is off\n", __func__); | |
| 455 | − | |
| 456 | − return 0; | |
| 457 | −} | |
| 458 | − | |
| 459 | −static int noon010_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 460 | −{ | |
| 461 | − struct v4l2_subdev *sd = to_sd(ctrl); | |
| 462 | − struct noon010_info *info = to_noon010(sd); | |
| 463 | − int ret = 0; | |
| 464 | − | |
| 465 | − v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n", | |
| 466 | − __func__, ctrl->id, ctrl->val); | |
| 467 | − | |
| 468 | − mutex_lock(&info->lock); | |
| 469 | − /* | |
| 470 | − * If the device is not powered up by the host driver do | |
| 471 | − * not apply any controls to H/W at this time. Instead | |
| 472 | − * the controls will be restored right after power-up. | |
| 473 | − */ | |
| 474 | − if (!info->power) | |
| 475 | − goto unlock; | |
| 476 | − | |
| 477 | − switch (ctrl->id) { | |
| 478 | − case V4L2_CID_AUTO_WHITE_BALANCE: | |
| 479 | − ret = noon010_enable_autowhitebalance(sd, ctrl->val); | |
| 480 | − break; | |
| 481 | − case V4L2_CID_BLUE_BALANCE: | |
| 482 | − ret = cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val); | |
| 483 | − break; | |
| 484 | − case V4L2_CID_RED_BALANCE: | |
| 485 | − ret = cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val); | |
| 486 | − break; | |
| 487 | − default: | |
| 488 | − ret = -EINVAL; | |
| 489 | − } | |
| 490 | −unlock: | |
| 491 | − mutex_unlock(&info->lock); | |
| 492 | − return ret; | |
| 493 | −} | |
| 494 | − | |
| 495 | −static int noon010_enum_mbus_code(struct v4l2_subdev *sd, | |
| 496 | − struct v4l2_subdev_state *sd_state, | |
| 497 | − struct v4l2_subdev_mbus_code_enum *code) | |
| 498 | −{ | |
| 499 | − if (code->index >= ARRAY_SIZE(noon010_formats)) | |
| 500 | − return -EINVAL; | |
| 501 | − | |
| 502 | − code->code = noon010_formats[code->index].code; | |
| 503 | − return 0; | |
| 504 | −} | |
| 505 | − | |
| 506 | −static int noon010_get_fmt(struct v4l2_subdev *sd, | |
| 507 | − struct v4l2_subdev_state *sd_state, | |
| 508 | − struct v4l2_subdev_format *fmt) | |
| 509 | −{ | |
| 510 | − struct noon010_info *info = to_noon010(sd); | |
| 511 | − struct v4l2_mbus_framefmt *mf; | |
| 512 | − | |
| 513 | − if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
| 514 | − if (sd_state) { | |
| 515 | − mf = v4l2_subdev_get_try_format(sd, sd_state, 0); | |
| 516 | − fmt->format = *mf; | |
| 517 | − } | |
| 518 | − return 0; | |
| 519 | − } | |
| 520 | − mf = &fmt->format; | |
| 521 | − | |
| 522 | − mutex_lock(&info->lock); | |
| 523 | − mf->width = info->curr_win->width; | |
| 524 | − mf->height = info->curr_win->height; | |
| 525 | − mf->code = info->curr_fmt->code; | |
| 526 | − mf->colorspace = info->curr_fmt->colorspace; | |
| 527 | − mf->field = V4L2_FIELD_NONE; | |
| 528 | − | |
| 529 | − mutex_unlock(&info->lock); | |
| 530 | − return 0; | |
| 531 | −} | |
| 532 | − | |
| 533 | −/* Return nearest media bus frame format. */ | |
| 534 | −static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd, | |
| 535 | − struct v4l2_mbus_framefmt *mf) | |
| 536 | −{ | |
| 537 | − int i = ARRAY_SIZE(noon010_formats); | |
| 538 | − | |
| 539 | − while (--i) | |
| 540 | − if (mf->code == noon010_formats[i].code) | |
| 541 | − break; | |
| 542 | − mf->code = noon010_formats[i].code; | |
| 543 | − | |
| 544 | − return &noon010_formats[i]; | |
| 545 | −} | |
| 546 | − | |
| 547 | −static int noon010_set_fmt(struct v4l2_subdev *sd, | |
| 548 | − struct v4l2_subdev_state *sd_state, | |
| 549 | − struct v4l2_subdev_format *fmt) | |
| 550 | −{ | |
| 551 | − struct noon010_info *info = to_noon010(sd); | |
| 552 | − const struct noon010_frmsize *size = NULL; | |
| 553 | − const struct noon010_format *nf; | |
| 554 | − struct v4l2_mbus_framefmt *mf; | |
| 555 | − int ret = 0; | |
| 556 | − | |
| 557 | − nf = noon010_try_fmt(sd, &fmt->format); | |
| 558 | − noon010_try_frame_size(&fmt->format, &size); | |
| 559 | − fmt->format.colorspace = V4L2_COLORSPACE_JPEG; | |
| 560 | − fmt->format.field = V4L2_FIELD_NONE; | |
| 561 | − | |
| 562 | − if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
| 563 | − if (sd_state) { | |
| 564 | − mf = v4l2_subdev_get_try_format(sd, sd_state, 0); | |
| 565 | − *mf = fmt->format; | |
| 566 | − } | |
| 567 | − return 0; | |
| 568 | − } | |
| 569 | − mutex_lock(&info->lock); | |
| 570 | − if (!info->streaming) { | |
| 571 | − info->apply_new_cfg = 1; | |
| 572 | − info->curr_fmt = nf; | |
| 573 | − info->curr_win = size; | |
| 574 | − } else { | |
| 575 | − ret = -EBUSY; | |
| 576 | − } | |
| 577 | − mutex_unlock(&info->lock); | |
| 578 | − return ret; | |
| 579 | −} | |
| 580 | − | |
| 581 | −/* Called with struct noon010_info.lock mutex held */ | |
| 582 | −static int noon010_base_config(struct v4l2_subdev *sd) | |
| 583 | −{ | |
| 584 | − int ret = noon010_bulk_write_reg(sd, noon010_base_regs); | |
| 585 | − if (!ret) | |
| 586 | − ret = noon010_set_params(sd); | |
| 587 | − if (!ret) | |
| 588 | − ret = noon010_set_flip(sd, 1, 0); | |
| 589 | − | |
| 590 | − return ret; | |
| 591 | −} | |
| 592 | − | |
| 593 | −static int noon010_s_power(struct v4l2_subdev *sd, int on) | |
| 594 | −{ | |
| 595 | − struct noon010_info *info = to_noon010(sd); | |
| 596 | − int ret; | |
| 597 | − | |
| 598 | − mutex_lock(&info->lock); | |
| 599 | − if (on) { | |
| 600 | − ret = power_enable(info); | |
| 601 | − if (!ret) | |
| 602 | − ret = noon010_base_config(sd); | |
| 603 | − } else { | |
| 604 | − noon010_power_ctrl(sd, false, true); | |
| 605 | − ret = power_disable(info); | |
| 606 | − } | |
| 607 | − mutex_unlock(&info->lock); | |
| 608 | − | |
| 609 | − /* Restore the controls state */ | |
| 610 | − if (!ret && on) | |
| 611 | − ret = v4l2_ctrl_handler_setup(&info->hdl); | |
| 612 | − | |
| 613 | − return ret; | |
| 614 | −} | |
| 615 | − | |
| 616 | −static int noon010_s_stream(struct v4l2_subdev *sd, int on) | |
| 617 | −{ | |
| 618 | − struct noon010_info *info = to_noon010(sd); | |
| 619 | − int ret = 0; | |
| 620 | − | |
| 621 | − mutex_lock(&info->lock); | |
| 622 | − if (!info->streaming != !on) { | |
| 623 | − ret = noon010_power_ctrl(sd, false, !on); | |
| 624 | − if (!ret) | |
| 625 | − info->streaming = on; | |
| 626 | − } | |
| 627 | − if (!ret && on && info->apply_new_cfg) { | |
| 628 | − ret = noon010_set_params(sd); | |
| 629 | − if (!ret) | |
| 630 | − info->apply_new_cfg = 0; | |
| 631 | − } | |
| 632 | − mutex_unlock(&info->lock); | |
| 633 | − return ret; | |
| 634 | −} | |
| 635 | − | |
| 636 | −static int noon010_log_status(struct v4l2_subdev *sd) | |
| 637 | −{ | |
| 638 | − struct noon010_info *info = to_noon010(sd); | |
| 639 | − | |
| 640 | − v4l2_ctrl_handler_log_status(&info->hdl, sd->name); | |
| 641 | − return 0; | |
| 642 | −} | |
| 643 | − | |
| 644 | −static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 645 | −{ | |
| 646 | − struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, | |
| 647 | − fh->state, | |
| 648 | − 0); | |
| 649 | − | |
| 650 | − mf->width = noon010_sizes[0].width; | |
| 651 | − mf->height = noon010_sizes[0].height; | |
| 652 | − mf->code = noon010_formats[0].code; | |
| 653 | − mf->colorspace = V4L2_COLORSPACE_JPEG; | |
| 654 | − mf->field = V4L2_FIELD_NONE; | |
| 655 | − return 0; | |
| 656 | −} | |
| 657 | − | |
| 658 | −static const struct v4l2_subdev_internal_ops noon010_subdev_internal_ops = { | |
| 659 | − .open = noon010_open, | |
| 660 | −}; | |
| 661 | − | |
| 662 | −static const struct v4l2_ctrl_ops noon010_ctrl_ops = { | |
| 663 | − .s_ctrl = noon010_s_ctrl, | |
| 664 | −}; | |
| 665 | − | |
| 666 | −static const struct v4l2_subdev_core_ops noon010_core_ops = { | |
| 667 | − .s_power = noon010_s_power, | |
| 668 | − .log_status = noon010_log_status, | |
| 669 | −}; | |
| 670 | − | |
| 671 | −static const struct v4l2_subdev_pad_ops noon010_pad_ops = { | |
| 672 | − .enum_mbus_code = noon010_enum_mbus_code, | |
| 673 | − .get_fmt = noon010_get_fmt, | |
| 674 | − .set_fmt = noon010_set_fmt, | |
| 675 | −}; | |
| 676 | − | |
| 677 | −static const struct v4l2_subdev_video_ops noon010_video_ops = { | |
| 678 | − .s_stream = noon010_s_stream, | |
| 679 | −}; | |
| 680 | − | |
| 681 | −static const struct v4l2_subdev_ops noon010_ops = { | |
| 682 | − .core = &noon010_core_ops, | |
| 683 | − .pad = &noon010_pad_ops, | |
| 684 | − .video = &noon010_video_ops, | |
| 685 | −}; | |
| 686 | − | |
| 687 | −/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */ | |
| 688 | −static int noon010_detect(struct i2c_client *client, struct noon010_info *info) | |
| 689 | −{ | |
| 690 | − int ret; | |
| 691 | − | |
| 692 | − ret = power_enable(info); | |
| 693 | − if (ret) | |
| 694 | − return ret; | |
| 695 | − | |
| 696 | − ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG); | |
| 697 | − if (ret < 0) | |
| 698 | − dev_err(&client->dev, "I2C read failed: 0x%X\n", ret); | |
| 699 | − | |
| 700 | − power_disable(info); | |
| 701 | − | |
| 702 | − return ret == NOON010PC30_ID ? 0 : -ENODEV; | |
| 703 | −} | |
| 704 | − | |
| 705 | −static int noon010_probe(struct i2c_client *client) | |
| 706 | −{ | |
| 707 | − struct noon010_info *info; | |
| 708 | − struct v4l2_subdev *sd; | |
| 709 | − const struct noon010pc30_platform_data *pdata | |
| 710 | − = client->dev.platform_data; | |
| 711 | − int ret; | |
| 712 | − int i; | |
| 713 | − | |
| 714 | − if (!pdata) { | |
| 715 | − dev_err(&client->dev, "No platform data!\n"); | |
| 716 | − return -EIO; | |
| 717 | − } | |
| 718 | − | |
| 719 | − info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); | |
| 720 | − if (!info) | |
| 721 | − return -ENOMEM; | |
| 722 | − | |
| 723 | − mutex_init(&info->lock); | |
| 724 | − sd = &info->sd; | |
| 725 | − v4l2_i2c_subdev_init(sd, client, &noon010_ops); | |
| 726 | − /* Static name; NEVER use in new drivers! */ | |
| 727 | − strscpy(sd->name, MODULE_NAME, sizeof(sd->name)); | |
| 728 | − | |
| 729 | − sd->internal_ops = &noon010_subdev_internal_ops; | |
| 730 | − sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 731 | − | |
| 732 | − v4l2_ctrl_handler_init(&info->hdl, 3); | |
| 733 | − | |
| 734 | − v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, | |
| 735 | − V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | |
| 736 | − v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, | |
| 737 | − V4L2_CID_RED_BALANCE, 0, 127, 1, 64); | |
| 738 | − v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, | |
| 739 | − V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64); | |
| 740 | − | |
| 741 | − sd->ctrl_handler = &info->hdl; | |
| 742 | − | |
| 743 | − ret = info->hdl.error; | |
| 744 | − if (ret) | |
| 745 | − goto np_err; | |
| 746 | − | |
| 747 | − info->i2c_reg_page = -1; | |
| 748 | − info->curr_fmt = &noon010_formats[0]; | |
| 749 | − info->curr_win = &noon010_sizes[0]; | |
| 750 | − | |
| 751 | − /* Request reset asserted so we get put into reset */ | |
| 752 | − info->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); | |
| 753 | − if (IS_ERR(info->reset)) { | |
| 754 | − ret = PTR_ERR(info->reset); | |
| 755 | − goto np_err; | |
| 756 | − } | |
| 757 | − gpiod_set_consumer_name(info->reset, "NOON010PC30 NRST"); | |
| 758 | − | |
| 759 | − /* Request standby asserted so we get put into standby */ | |
| 760 | − info->stby = devm_gpiod_get(&client->dev, "standby", GPIOD_OUT_HIGH); | |
| 761 | − if (IS_ERR(info->stby)) { | |
| 762 | − ret = PTR_ERR(info->stby); | |
| 763 | − goto np_err; | |
| 764 | − } | |
| 765 | − gpiod_set_consumer_name(info->reset, "NOON010PC30 STBY"); | |
| 766 | − | |
| 767 | − for (i = 0; i < NOON010_NUM_SUPPLIES; i++) | |
| 768 | − info->supply[i].supply = noon010_supply_name[i]; | |
| 769 | − | |
| 770 | − ret = devm_regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES, | |
| 771 | − info->supply); | |
| 772 | − if (ret) | |
| 773 | − goto np_err; | |
| 774 | − | |
| 775 | − info->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 776 | − sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 777 | − ret = media_entity_pads_init(&sd->entity, 1, &info->pad); | |
| 778 | − if (ret < 0) | |
| 779 | − goto np_err; | |
| 780 | − | |
| 781 | − ret = noon010_detect(client, info); | |
| 782 | − if (!ret) | |
| 783 | − return 0; | |
| 784 | − | |
| 785 | −np_err: | |
| 786 | − v4l2_ctrl_handler_free(&info->hdl); | |
| 787 | − v4l2_device_unregister_subdev(sd); | |
| 788 | − return ret; | |
| 789 | −} | |
| 790 | − | |
| 791 | −static void noon010_remove(struct i2c_client *client) | |
| 792 | −{ | |
| 793 | − struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 794 | − struct noon010_info *info = to_noon010(sd); | |
| 795 | − | |
| 796 | − v4l2_device_unregister_subdev(sd); | |
| 797 | − v4l2_ctrl_handler_free(&info->hdl); | |
| 798 | − media_entity_cleanup(&sd->entity); | |
| 799 | −} | |
| 800 | − | |
| 801 | −static const struct i2c_device_id noon010_id[] = { | |
| 802 | − { MODULE_NAME, 0 }, | |
| 803 | − { }, | |
| 804 | −}; | |
| 805 | −MODULE_DEVICE_TABLE(i2c, noon010_id); | |
| 806 | − | |
| 807 | − | |
| 808 | −static struct i2c_driver noon010_i2c_driver = { | |
| 809 | − .driver = { | |
| 810 | − .name = MODULE_NAME | |
| 811 | − }, | |
| 812 | − .probe_new = noon010_probe, | |
| 813 | − .remove = noon010_remove, | |
| 814 | − .id_table = noon010_id, | |
| 815 | −}; | |
| 816 | − | |
| 817 | −module_i2c_driver(noon010_i2c_driver); | |
| 818 | − | |
| 819 | −MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); | |
| 820 | −MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | |
| 821 | −MODULE_LICENSE("GPL"); | |
| @@ -243,7 +243,6 @@ static const struct ov13b10_reg mipi_data_rate_1120mbps[] = { · 242 unmodified lines | ||
| 243 | 243 | {0x5047, 0xa4}, |
| 244 | 244 | {0x5048, 0x20}, |
| 245 | 245 | {0x5049, 0xa4}, |
| 246 | − {0x0100, 0x01}, | |
| 247 | 246 | }; |
| 248 | 247 | |
| 249 | 248 | static const struct ov13b10_reg mode_4208x3120_regs[] = { |
| @@ -589,6 +588,9 @@ struct ov13b10 { · 339 unmodified lines | ||
| 589 | 588 | |
| 590 | 589 | /* Streaming on/off */ |
| 591 | 590 | bool streaming; |
| 591 | + | |
| 592 | + /* True if the device has been identified */ | |
| 593 | + bool identified; | |
| 592 | 594 | }; |
| 593 | 595 | |
| 594 | 596 | #define to_ov13b10(_sd) container_of(_sd, struct ov13b10, sd) |
| @@ -1023,12 +1025,42 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd, · 428 unmodified lines | ||
| 1023 | 1025 | return 0; |
| 1024 | 1026 | } |
| 1025 | 1027 | |
| 1028 | +/* Verify chip ID */ | |
| 1029 | +static int ov13b10_identify_module(struct ov13b10 *ov13b) | |
| 1030 | +{ | |
| 1031 | + struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); | |
| 1032 | + int ret; | |
| 1033 | + u32 val; | |
| 1034 | + | |
| 1035 | + if (ov13b->identified) | |
| 1036 | + return 0; | |
| 1037 | + | |
| 1038 | + ret = ov13b10_read_reg(ov13b, OV13B10_REG_CHIP_ID, | |
| 1039 | + OV13B10_REG_VALUE_24BIT, &val); | |
| 1040 | + if (ret) | |
| 1041 | + return ret; | |
| 1042 | + | |
| 1043 | + if (val != OV13B10_CHIP_ID) { | |
| 1044 | + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", | |
| 1045 | + OV13B10_CHIP_ID, val); | |
| 1046 | + return -EIO; | |
| 1047 | + } | |
| 1048 | + | |
| 1049 | + ov13b->identified = true; | |
| 1050 | + | |
| 1051 | + return 0; | |
| 1052 | +} | |
| 1053 | + | |
| 1026 | 1054 | static int ov13b10_start_streaming(struct ov13b10 *ov13b) |
| 1027 | 1055 | { |
| 1028 | 1056 | struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); |
| 1029 | 1057 | const struct ov13b10_reg_list *reg_list; |
| 1030 | 1058 | int ret, link_freq_index; |
| 1031 | 1059 | |
| 1060 | + ret = ov13b10_identify_module(ov13b); | |
| 1061 | + if (ret) | |
| 1062 | + return ret; | |
| 1063 | + | |
| 1032 | 1064 | /* Get out of from software reset */ |
| 1033 | 1065 | ret = ov13b10_write_reg(ov13b, OV13B10_REG_SOFTWARE_RST, |
| 1034 | 1066 | OV13B10_REG_VALUE_08BIT, OV13B10_SOFTWARE_RST); |
| @@ -1144,27 +1176,6 @@ error: · 109 unmodified lines | ||
| 1144 | 1176 | return ret; |
| 1145 | 1177 | } |
| 1146 | 1178 | |
| 1147 | −/* Verify chip ID */ | |
| 1148 | −static int ov13b10_identify_module(struct ov13b10 *ov13b) | |
| 1149 | −{ | |
| 1150 | − struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); | |
| 1151 | − int ret; | |
| 1152 | − u32 val; | |
| 1153 | − | |
| 1154 | − ret = ov13b10_read_reg(ov13b, OV13B10_REG_CHIP_ID, | |
| 1155 | − OV13B10_REG_VALUE_24BIT, &val); | |
| 1156 | − if (ret) | |
| 1157 | − return ret; | |
| 1158 | − | |
| 1159 | − if (val != OV13B10_CHIP_ID) { | |
| 1160 | − dev_err(&client->dev, "chip id mismatch: %x!=%x\n", | |
| 1161 | − OV13B10_CHIP_ID, val); | |
| 1162 | − return -EIO; | |
| 1163 | − } | |
| 1164 | − | |
| 1165 | − return 0; | |
| 1166 | −} | |
| 1167 | − | |
| 1168 | 1179 | static const struct v4l2_subdev_video_ops ov13b10_video_ops = { |
| 1169 | 1180 | .s_stream = ov13b10_set_stream, |
| 1170 | 1181 | }; |
| @@ -1379,6 +1390,7 @@ out_err: · 208 unmodified lines | ||
| 1379 | 1390 | static int ov13b10_probe(struct i2c_client *client) |
| 1380 | 1391 | { |
| 1381 | 1392 | struct ov13b10 *ov13b; |
| 1393 | + bool full_power; | |
| 1382 | 1394 | int ret; |
| 1383 | 1395 | |
| 1384 | 1396 | /* Check HW config */ |
| @@ -1395,11 +1407,14 @@ static int ov13b10_probe(struct i2c_client *client) · 10 unmodified lines | ||
| 1395 | 1407 | /* Initialize subdev */ |
| 1396 | 1408 | v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops); |
| 1397 | 1409 | |
| 1398 | − /* Check module identity */ | |
| 1399 | − ret = ov13b10_identify_module(ov13b); | |
| 1400 | − if (ret) { | |
| 1401 | − dev_err(&client->dev, "failed to find sensor: %d\n", ret); | |
| 1402 | − return ret; | |
| 1410 | + full_power = acpi_dev_state_d0(&client->dev); | |
| 1411 | + if (full_power) { | |
| 1412 | + /* Check module identity */ | |
| 1413 | + ret = ov13b10_identify_module(ov13b); | |
| 1414 | + if (ret) { | |
| 1415 | + dev_err(&client->dev, "failed to find sensor: %d\n", ret); | |
| 1416 | + return ret; | |
| 1417 | + } | |
| 1403 | 1418 | } |
| 1404 | 1419 | |
| 1405 | 1420 | /* Set default mode to max resolution */ |
| @@ -1431,7 +1446,10 @@ static int ov13b10_probe(struct i2c_client *client) · 25 unmodified lines | ||
| 1431 | 1446 | * Device is already turned on by i2c-core with ACPI domain PM. |
| 1432 | 1447 | * Enable runtime PM and turn off the device. |
| 1433 | 1448 | */ |
| 1434 | − pm_runtime_set_active(&client->dev); | |
| 1449 | + | |
| 1450 | + /* Set the device's state to active if it's in D0 state. */ | |
| 1451 | + if (full_power) | |
| 1452 | + pm_runtime_set_active(&client->dev); | |
| 1435 | 1453 | pm_runtime_enable(&client->dev); |
| 1436 | 1454 | pm_runtime_idle(&client->dev); |
| 1437 | 1455 | |
| @@ -1480,6 +1498,7 @@ static struct i2c_driver ov13b10_i2c_driver = { · 42 unmodified lines | ||
| 1480 | 1498 | }, |
| 1481 | 1499 | .probe_new = ov13b10_probe, |
| 1482 | 1500 | .remove = ov13b10_remove, |
| 1501 | + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, | |
| 1483 | 1502 | }; |
| 1484 | 1503 | |
| 1485 | 1504 | module_i2c_driver(ov13b10_i2c_driver); |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <media/media-entity.h> |
| 18 | 18 | #include <media/v4l2-async.h> |
| 19 | 19 | #include <media/v4l2-ctrls.h> |
| 20 | +#include <media/v4l2-fwnode.h> | |
| 20 | 21 | #include <media/v4l2-subdev.h> |
| 21 | 22 | |
| 22 | 23 | #define CHIP_ID 0x2685 |
| @@ -55,6 +56,9 @@ · 32 unmodified lines | ||
| 55 | 56 | #define OV2685_REG_VALUE_16BIT 2 |
| 56 | 57 | #define OV2685_REG_VALUE_24BIT 3 |
| 57 | 58 | |
| 59 | +#define OV2685_NATIVE_WIDTH 1616 | |
| 60 | +#define OV2685_NATIVE_HEIGHT 1216 | |
| 61 | + | |
| 58 | 62 | #define OV2685_LANES 1 |
| 59 | 63 | #define OV2685_BITS_PER_SAMPLE 10 |
| 60 | 64 | |
| @@ -77,6 +81,7 @@ struct ov2685_mode { · 16 unmodified lines | ||
| 77 | 81 | u32 exp_def; |
| 78 | 82 | u32 hts_def; |
| 79 | 83 | u32 vts_def; |
| 84 | + const struct v4l2_rect *analog_crop; | |
| 80 | 85 | const struct regval *reg_list; |
| 81 | 86 | }; |
| 82 | 87 | |
| @@ -230,6 +235,13 @@ static const int ov2685_test_pattern_val[] = { · 147 unmodified lines | ||
| 230 | 235 | OV2685_TEST_PATTERN_COLOR_SQUARE, |
| 231 | 236 | }; |
| 232 | 237 | |
| 238 | +static const struct v4l2_rect ov2685_analog_crop = { | |
| 239 | + .left = 8, | |
| 240 | + .top = 8, | |
| 241 | + .width = 1600, | |
| 242 | + .height = 1200, | |
| 243 | +}; | |
| 244 | + | |
| 233 | 245 | static const struct ov2685_mode supported_modes[] = { |
| 234 | 246 | { |
| 235 | 247 | .width = 1600, |
| @@ -237,6 +249,7 @@ static const struct ov2685_mode supported_modes[] = { · 1 unmodified line | ||
| 237 | 249 | .exp_def = 0x04ee, |
| 238 | 250 | .hts_def = 0x06a4, |
| 239 | 251 | .vts_def = 0x050e, |
| 252 | + .analog_crop = &ov2685_analog_crop, | |
| 240 | 253 | .reg_list = ov2685_1600x1200_regs, |
| 241 | 254 | }, |
| 242 | 255 | }; |
| @@ -383,6 +396,53 @@ static int ov2685_enum_frame_sizes(struct v4l2_subdev *sd, · 140 unmodified lines | ||
| 383 | 396 | return 0; |
| 384 | 397 | } |
| 385 | 398 | |
| 399 | +static const struct v4l2_rect * | |
| 400 | +__ov2685_get_pad_crop(struct ov2685 *ov2685, | |
| 401 | + struct v4l2_subdev_state *state, unsigned int pad, | |
| 402 | + enum v4l2_subdev_format_whence which) | |
| 403 | +{ | |
| 404 | + const struct ov2685_mode *mode = ov2685->cur_mode; | |
| 405 | + | |
| 406 | + switch (which) { | |
| 407 | + case V4L2_SUBDEV_FORMAT_TRY: | |
| 408 | + return v4l2_subdev_get_try_crop(&ov2685->subdev, state, pad); | |
| 409 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 410 | + return mode->analog_crop; | |
| 411 | + } | |
| 412 | + | |
| 413 | + return NULL; | |
| 414 | +} | |
| 415 | + | |
| 416 | +static int ov2685_get_selection(struct v4l2_subdev *sd, | |
| 417 | + struct v4l2_subdev_state *sd_state, | |
| 418 | + struct v4l2_subdev_selection *sel) | |
| 419 | +{ | |
| 420 | + struct ov2685 *ov2685 = to_ov2685(sd); | |
| 421 | + | |
| 422 | + switch (sel->target) { | |
| 423 | + case V4L2_SEL_TGT_CROP: | |
| 424 | + mutex_lock(&ov2685->mutex); | |
| 425 | + sel->r = *__ov2685_get_pad_crop(ov2685, sd_state, sel->pad, | |
| 426 | + sel->which); | |
| 427 | + mutex_unlock(&ov2685->mutex); | |
| 428 | + break; | |
| 429 | + case V4L2_SEL_TGT_NATIVE_SIZE: | |
| 430 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 431 | + sel->r.top = 0; | |
| 432 | + sel->r.left = 0; | |
| 433 | + sel->r.width = OV2685_NATIVE_WIDTH; | |
| 434 | + sel->r.height = OV2685_NATIVE_HEIGHT; | |
| 435 | + break; | |
| 436 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 437 | + sel->r = ov2685_analog_crop; | |
| 438 | + break; | |
| 439 | + default: | |
| 440 | + return -EINVAL; | |
| 441 | + } | |
| 442 | + | |
| 443 | + return 0; | |
| 444 | +} | |
| 445 | + | |
| 386 | 446 | /* Calculate the delay in us by clock rate and clock cycles */ |
| 387 | 447 | static inline u32 ov2685_cal_delay(u32 cycles) |
| 388 | 448 | { |
| @@ -419,8 +479,10 @@ static int __ov2685_power_on(struct ov2685 *ov2685) · 30 unmodified lines | ||
| 419 | 479 | * writing register before .s_stream() as a workaround |
| 420 | 480 | */ |
| 421 | 481 | ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list); |
| 422 | − if (ret) | |
| 482 | + if (ret) { | |
| 483 | + dev_err(dev, "Failed to set regs for power on\n"); | |
| 423 | 484 | goto disable_supplies; |
| 485 | + } | |
| 424 | 486 | |
| 425 | 487 | return 0; |
| 426 | 488 | |
| @@ -589,6 +651,8 @@ static const struct v4l2_subdev_pad_ops ov2685_pad_ops = { · 162 unmodified lines | ||
| 589 | 651 | .enum_frame_size = ov2685_enum_frame_sizes, |
| 590 | 652 | .get_fmt = ov2685_get_fmt, |
| 591 | 653 | .set_fmt = ov2685_set_fmt, |
| 654 | + .get_selection = ov2685_get_selection, | |
| 655 | + .set_selection = ov2685_get_selection, | |
| 592 | 656 | }; |
| 593 | 657 | |
| 594 | 658 | static const struct v4l2_subdev_ops ov2685_subdev_ops = { |
| @@ -611,13 +675,14 @@ static int ov2685_initialize_controls(struct ov2685 *ov2685) · 16 unmodified lines | ||
| 611 | 675 | const struct ov2685_mode *mode; |
| 612 | 676 | struct v4l2_ctrl_handler *handler; |
| 613 | 677 | struct v4l2_ctrl *ctrl; |
| 678 | + struct v4l2_fwnode_device_properties props; | |
| 614 | 679 | u64 exposure_max; |
| 615 | 680 | u32 pixel_rate, h_blank; |
| 616 | 681 | int ret; |
| 617 | 682 | |
| 618 | 683 | handler = &ov2685->ctrl_handler; |
| 619 | 684 | mode = ov2685->cur_mode; |
| 620 | − ret = v4l2_ctrl_handler_init(handler, 8); | |
| 685 | + ret = v4l2_ctrl_handler_init(handler, 10); | |
| 621 | 686 | if (ret) |
| 622 | 687 | return ret; |
| 623 | 688 | handler->lock = &ov2685->mutex; |
| @@ -659,6 +724,15 @@ static int ov2685_initialize_controls(struct ov2685 *ov2685) · 35 unmodified lines | ||
| 659 | 724 | ARRAY_SIZE(ov2685_test_pattern_menu) - 1, |
| 660 | 725 | 0, 0, ov2685_test_pattern_menu); |
| 661 | 726 | |
| 727 | + /* set properties from fwnode (e.g. rotation, orientation) */ | |
| 728 | + ret = v4l2_fwnode_device_parse(&ov2685->client->dev, &props); | |
| 729 | + if (ret) | |
| 730 | + goto err_free_handler; | |
| 731 | + | |
| 732 | + ret = v4l2_ctrl_new_fwnode_properties(handler, &ov2685_ctrl_ops, &props); | |
| 733 | + if (ret) | |
| 734 | + goto err_free_handler; | |
| 735 | + | |
| 662 | 736 | if (handler->error) { |
| 663 | 737 | ret = handler->error; |
| 664 | 738 | dev_err(&ov2685->client->dev, |
| @@ -733,7 +807,7 @@ static int ov2685_probe(struct i2c_client *client) · 68 unmodified lines | ||
| 733 | 807 | if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ) |
| 734 | 808 | dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); |
| 735 | 809 | |
| 736 | − ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
| 810 | + ov2685->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | |
| 737 | 811 | if (IS_ERR(ov2685->reset_gpio)) { |
| 738 | 812 | dev_err(dev, "Failed to get reset-gpios\n"); |
| 739 | 813 | return -EINVAL; |
| @@ -58,6 +58,7 @@ · 57 unmodified lines | ||
| 58 | 58 | #define OV5647_REG_MIPI_CTRL00 0x4800 |
| 59 | 59 | #define OV5647_REG_MIPI_CTRL14 0x4814 |
| 60 | 60 | #define OV5647_REG_AWB 0x5001 |
| 61 | +#define OV5647_REG_ISPCTRL3D 0x503d | |
| 61 | 62 | |
| 62 | 63 | #define REG_TERM 0xfffe |
| 63 | 64 | #define VAL_TERM 0xfe |
| @@ -116,6 +117,20 @@ static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd) · 52 unmodified lines | ||
| 116 | 117 | return container_of(sd, struct ov5647, sd); |
| 117 | 118 | } |
| 118 | 119 | |
| 120 | +static const char * const ov5647_test_pattern_menu[] = { | |
| 121 | + "Disabled", | |
| 122 | + "Color Bars", | |
| 123 | + "Color Squares", | |
| 124 | + "Random Data", | |
| 125 | +}; | |
| 126 | + | |
| 127 | +static const u8 ov5647_test_pattern_val[] = { | |
| 128 | + 0x00, /* Disabled */ | |
| 129 | + 0x80, /* Color Bars */ | |
| 130 | + 0x82, /* Color Squares */ | |
| 131 | + 0x81, /* Random Data */ | |
| 132 | +}; | |
| 133 | + | |
| 119 | 134 | static const struct regval_list sensor_oe_disable_regs[] = { |
| 120 | 135 | {0x3000, 0x00}, |
| 121 | 136 | {0x3001, 0x00}, |
| @@ -614,23 +629,29 @@ static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) · 492 unmodified lines | ||
| 614 | 629 | |
| 615 | 630 | static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val) |
| 616 | 631 | { |
| 617 | − unsigned char data_w[2] = { reg >> 8, reg & 0xff }; | |
| 618 | 632 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 633 | + u8 buf[2] = { reg >> 8, reg & 0xff }; | |
| 634 | + struct i2c_msg msg[2]; | |
| 619 | 635 | int ret; |
| 620 | 636 | |
| 621 | − ret = i2c_master_send(client, data_w, 2); | |
| 622 | − if (ret < 0) { | |
| 623 | − dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", | |
| 624 | − __func__, reg); | |
| 625 | − return ret; | |
| 637 | + msg[0].addr = client->addr; | |
| 638 | + msg[0].flags = client->flags; | |
| 639 | + msg[0].buf = buf; | |
| 640 | + msg[0].len = sizeof(buf); | |
| 641 | + | |
| 642 | + msg[1].addr = client->addr; | |
| 643 | + msg[1].flags = client->flags | I2C_M_RD; | |
| 644 | + msg[1].buf = buf; | |
| 645 | + msg[1].len = 1; | |
| 646 | + | |
| 647 | + ret = i2c_transfer(client->adapter, msg, 2); | |
| 648 | + if (ret != 2) { | |
| 649 | + dev_err(&client->dev, "%s: i2c read error, reg: %x = %d\n", | |
| 650 | + __func__, reg, ret); | |
| 651 | + return ret >= 0 ? -EINVAL : ret; | |
| 626 | 652 | } |
| 627 | 653 | |
| 628 | − ret = i2c_master_recv(client, val, 1); | |
| 629 | − if (ret < 0) { | |
| 630 | − dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n", | |
| 631 | − __func__, reg); | |
| 632 | − return ret; | |
| 633 | − } | |
| 654 | + *val = buf[0]; | |
| 634 | 655 | |
| 635 | 656 | return 0; |
| 636 | 657 | } |
| @@ -1242,6 +1263,10 @@ static int ov5647_s_ctrl(struct v4l2_ctrl *ctrl) · 605 unmodified lines | ||
| 1242 | 1263 | ret = ov5647_write16(sd, OV5647_REG_VTS_HI, |
| 1243 | 1264 | sensor->mode->format.height + ctrl->val); |
| 1244 | 1265 | break; |
| 1266 | + case V4L2_CID_TEST_PATTERN: | |
| 1267 | + ret = ov5647_write(sd, OV5647_REG_ISPCTRL3D, | |
| 1268 | + ov5647_test_pattern_val[ctrl->val]); | |
| 1269 | + break; | |
| 1245 | 1270 | |
| 1246 | 1271 | /* Read-only, but we adjust it based on mode. */ |
| 1247 | 1272 | case V4L2_CID_PIXEL_RATE: |
| @@ -1270,7 +1295,7 @@ static int ov5647_init_controls(struct ov5647 *sensor) · 22 unmodified lines | ||
| 1270 | 1295 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); |
| 1271 | 1296 | int hblank, exposure_max, exposure_def; |
| 1272 | 1297 | |
| 1273 | − v4l2_ctrl_handler_init(&sensor->ctrls, 8); | |
| 1298 | + v4l2_ctrl_handler_init(&sensor->ctrls, 9); | |
| 1274 | 1299 | |
| 1275 | 1300 | v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, |
| 1276 | 1301 | V4L2_CID_AUTOGAIN, 0, 1, 1, 0); |
| @@ -1314,6 +1339,11 @@ static int ov5647_init_controls(struct ov5647 *sensor) · 37 unmodified lines | ||
| 1314 | 1339 | sensor->mode->vts - |
| 1315 | 1340 | sensor->mode->format.height); |
| 1316 | 1341 | |
| 1342 | + v4l2_ctrl_new_std_menu_items(&sensor->ctrls, &ov5647_ctrl_ops, | |
| 1343 | + V4L2_CID_TEST_PATTERN, | |
| 1344 | + ARRAY_SIZE(ov5647_test_pattern_menu) - 1, | |
| 1345 | + 0, 0, ov5647_test_pattern_menu); | |
| 1346 | + | |
| 1317 | 1347 | if (sensor->ctrls.error) |
| 1318 | 1348 | goto handler_free; |
| 1319 | 1349 | |
| @@ -29,6 +29,12 @@ · 28 unmodified lines | ||
| 29 | 29 | #define OV5670_REG_SOFTWARE_RST 0x0103 |
| 30 | 30 | #define OV5670_SOFTWARE_RST 0x01 |
| 31 | 31 | |
| 32 | +#define OV5670_MIPI_SC_CTRL0_REG 0x3018 | |
| 33 | +#define OV5670_MIPI_SC_CTRL0_LANES(v) ((((v) - 1) << 5) & \ | |
| 34 | + GENMASK(7, 5)) | |
| 35 | +#define OV5670_MIPI_SC_CTRL0_MIPI_EN BIT(4) | |
| 36 | +#define OV5670_MIPI_SC_CTRL0_RESERVED BIT(1) | |
| 37 | + | |
| 32 | 38 | /* vertical-timings from sensor */ |
| 33 | 39 | #define OV5670_REG_VTS 0x380e |
| 34 | 40 | #define OV5670_VTS_30FPS 0x0808 /* default for 30 fps */ |
| @@ -92,7 +98,6 @@ struct ov5670_reg_list { · 57 unmodified lines | ||
| 92 | 98 | }; |
| 93 | 99 | |
| 94 | 100 | struct ov5670_link_freq_config { |
| 95 | − u32 pixel_rate; | |
| 96 | 101 | const struct ov5670_reg_list reg_list; |
| 97 | 102 | }; |
| 98 | 103 | |
| @@ -163,7 +168,6 @@ static const struct ov5670_reg mode_2592x1944_regs[] = { · 64 unmodified lines | ||
| 163 | 168 | {0x3005, 0xf0}, |
| 164 | 169 | {0x3007, 0x00}, |
| 165 | 170 | {0x3015, 0x0f}, |
| 166 | − {0x3018, 0x32}, | |
| 167 | 171 | {0x301a, 0xf0}, |
| 168 | 172 | {0x301b, 0xf0}, |
| 169 | 173 | {0x301c, 0xf0}, |
| @@ -429,7 +433,6 @@ static const struct ov5670_reg mode_1296x972_regs[] = { · 259 unmodified lines | ||
| 429 | 433 | {0x3005, 0xf0}, |
| 430 | 434 | {0x3007, 0x00}, |
| 431 | 435 | {0x3015, 0x0f}, |
| 432 | − {0x3018, 0x32}, | |
| 433 | 436 | {0x301a, 0xf0}, |
| 434 | 437 | {0x301b, 0xf0}, |
| 435 | 438 | {0x301c, 0xf0}, |
| @@ -695,7 +698,6 @@ static const struct ov5670_reg mode_648x486_regs[] = { · 259 unmodified lines | ||
| 695 | 698 | {0x3005, 0xf0}, |
| 696 | 699 | {0x3007, 0x00}, |
| 697 | 700 | {0x3015, 0x0f}, |
| 698 | − {0x3018, 0x32}, | |
| 699 | 701 | {0x301a, 0xf0}, |
| 700 | 702 | {0x301b, 0xf0}, |
| 701 | 703 | {0x301c, 0xf0}, |
| @@ -961,7 +963,6 @@ static const struct ov5670_reg mode_2560x1440_regs[] = { · 259 unmodified lines | ||
| 961 | 963 | {0x3005, 0xf0}, |
| 962 | 964 | {0x3007, 0x00}, |
| 963 | 965 | {0x3015, 0x0f}, |
| 964 | − {0x3018, 0x32}, | |
| 965 | 966 | {0x301a, 0xf0}, |
| 966 | 967 | {0x301b, 0xf0}, |
| 967 | 968 | {0x301c, 0xf0}, |
| @@ -1226,7 +1227,6 @@ static const struct ov5670_reg mode_1280x720_regs[] = { · 258 unmodified lines | ||
| 1226 | 1227 | {0x3005, 0xf0}, |
| 1227 | 1228 | {0x3007, 0x00}, |
| 1228 | 1229 | {0x3015, 0x0f}, |
| 1229 | − {0x3018, 0x32}, | |
| 1230 | 1230 | {0x301a, 0xf0}, |
| 1231 | 1231 | {0x301b, 0xf0}, |
| 1232 | 1232 | {0x301c, 0xf0}, |
| @@ -1492,7 +1492,6 @@ static const struct ov5670_reg mode_640x360_regs[] = { · 259 unmodified lines | ||
| 1492 | 1492 | {0x3005, 0xf0}, |
| 1493 | 1493 | {0x3007, 0x00}, |
| 1494 | 1494 | {0x3015, 0x0f}, |
| 1495 | − {0x3018, 0x32}, | |
| 1496 | 1495 | {0x301a, 0xf0}, |
| 1497 | 1496 | {0x301b, 0xf0}, |
| 1498 | 1497 | {0x301c, 0xf0}, |
| @@ -1762,8 +1761,6 @@ static const char * const ov5670_test_pattern_menu[] = { · 263 unmodified lines | ||
| 1762 | 1761 | #define OV5670_LINK_FREQ_422MHZ_INDEX 0 |
| 1763 | 1762 | static const struct ov5670_link_freq_config link_freq_configs[] = { |
| 1764 | 1763 | { |
| 1765 | − /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ | |
| 1766 | − .pixel_rate = (OV5670_LINK_FREQ_422MHZ * 2 * 2) / 10, | |
| 1767 | 1764 | .reg_list = { |
| 1768 | 1765 | .num_of_regs = ARRAY_SIZE(mipi_data_rate_840mbps), |
| 1769 | 1766 | .regs = mipi_data_rate_840mbps, |
| @@ -1859,6 +1856,7 @@ static const struct ov5670_mode supported_modes[] = { · 89 unmodified lines | ||
| 1859 | 1856 | struct ov5670 { |
| 1860 | 1857 | struct v4l2_subdev sd; |
| 1861 | 1858 | struct media_pad pad; |
| 1859 | + struct v4l2_fwnode_endpoint endpoint; | |
| 1862 | 1860 | |
| 1863 | 1861 | struct v4l2_ctrl_handler ctrl_handler; |
| 1864 | 1862 | /* V4L2 Controls */ |
| @@ -2101,9 +2099,13 @@ static const struct v4l2_ctrl_ops ov5670_ctrl_ops = { · 236 unmodified lines | ||
| 2101 | 2099 | /* Initialize control handlers */ |
| 2102 | 2100 | static int ov5670_init_controls(struct ov5670 *ov5670) |
| 2103 | 2101 | { |
| 2102 | + struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = | |
| 2103 | + &ov5670->endpoint.bus.mipi_csi2; | |
| 2104 | 2104 | struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); |
| 2105 | 2105 | struct v4l2_fwnode_device_properties props; |
| 2106 | 2106 | struct v4l2_ctrl_handler *ctrl_hdlr; |
| 2107 | + unsigned int lanes_count; | |
| 2108 | + s64 mipi_pixel_rate; | |
| 2107 | 2109 | s64 vblank_max; |
| 2108 | 2110 | s64 vblank_def; |
| 2109 | 2111 | s64 vblank_min; |
| @@ -2124,12 +2126,15 @@ static int ov5670_init_controls(struct ov5670 *ov5670) · 14 unmodified lines | ||
| 2124 | 2126 | ov5670->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
| 2125 | 2127 | |
| 2126 | 2128 | /* By default, V4L2_CID_PIXEL_RATE is read only */ |
| 2129 | + lanes_count = bus_mipi_csi2->num_data_lanes; | |
| 2130 | + mipi_pixel_rate = OV5670_LINK_FREQ_422MHZ * 2 * lanes_count / 10; | |
| 2131 | + | |
| 2127 | 2132 | ov5670->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops, |
| 2128 | 2133 | V4L2_CID_PIXEL_RATE, |
| 2129 | − link_freq_configs[0].pixel_rate, | |
| 2130 | − link_freq_configs[0].pixel_rate, | |
| 2134 | + mipi_pixel_rate, | |
| 2135 | + mipi_pixel_rate, | |
| 2131 | 2136 | 1, |
| 2132 | − link_freq_configs[0].pixel_rate); | |
| 2137 | + mipi_pixel_rate); | |
| 2133 | 2138 | |
| 2134 | 2139 | vblank_max = OV5670_VTS_MAX - ov5670->cur_mode->height; |
| 2135 | 2140 | vblank_def = ov5670->cur_mode->vts_def - ov5670->cur_mode->height; |
| @@ -2288,8 +2293,13 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd, · 152 unmodified lines | ||
| 2288 | 2293 | struct v4l2_subdev_format *fmt) |
| 2289 | 2294 | { |
| 2290 | 2295 | struct ov5670 *ov5670 = to_ov5670(sd); |
| 2296 | + struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = | |
| 2297 | + &ov5670->endpoint.bus.mipi_csi2; | |
| 2291 | 2298 | const struct ov5670_mode *mode; |
| 2299 | + unsigned int lanes_count; | |
| 2300 | + s64 mipi_pixel_rate; | |
| 2292 | 2301 | s32 vblank_def; |
| 2302 | + s64 link_freq; | |
| 2293 | 2303 | s32 h_blank; |
| 2294 | 2304 | |
| 2295 | 2305 | mutex_lock(&ov5670->mutex); |
| @@ -2306,9 +2316,14 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd, · 10 unmodified lines | ||
| 2306 | 2316 | } else { |
| 2307 | 2317 | ov5670->cur_mode = mode; |
| 2308 | 2318 | __v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index); |
| 2319 | + | |
| 2320 | + lanes_count = bus_mipi_csi2->num_data_lanes; | |
| 2321 | + link_freq = link_freq_menu_items[mode->link_freq_index]; | |
| 2322 | + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ | |
| 2323 | + mipi_pixel_rate = div_s64(link_freq * 2 * lanes_count, 10); | |
| 2309 | 2324 | __v4l2_ctrl_s_ctrl_int64( |
| 2310 | 2325 | ov5670->pixel_rate, |
| 2311 | − link_freq_configs[mode->link_freq_index].pixel_rate); | |
| 2326 | + mipi_pixel_rate); | |
| 2312 | 2327 | /* Update limits and set FPS to default */ |
| 2313 | 2328 | vblank_def = ov5670->cur_mode->vts_def - |
| 2314 | 2329 | ov5670->cur_mode->height; |
| @@ -2361,6 +2376,19 @@ static int ov5670_identify_module(struct ov5670 *ov5670) · 46 unmodified lines | ||
| 2361 | 2376 | return 0; |
| 2362 | 2377 | } |
| 2363 | 2378 | |
| 2379 | +static int ov5670_mipi_configure(struct ov5670 *ov5670) | |
| 2380 | +{ | |
| 2381 | + struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = | |
| 2382 | + &ov5670->endpoint.bus.mipi_csi2; | |
| 2383 | + unsigned int lanes_count = bus_mipi_csi2->num_data_lanes; | |
| 2384 | + | |
| 2385 | + return ov5670_write_reg(ov5670, OV5670_MIPI_SC_CTRL0_REG, | |
| 2386 | + OV5670_REG_VALUE_08BIT, | |
| 2387 | + OV5670_MIPI_SC_CTRL0_LANES(lanes_count) | | |
| 2388 | + OV5670_MIPI_SC_CTRL0_MIPI_EN | | |
| 2389 | + OV5670_MIPI_SC_CTRL0_RESERVED); | |
| 2390 | +} | |
| 2391 | + | |
| 2364 | 2392 | /* Prepare streaming by writing default values and customized values */ |
| 2365 | 2393 | static int ov5670_start_streaming(struct ov5670 *ov5670) |
| 2366 | 2394 | { |
| @@ -2399,6 +2427,12 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) · 32 unmodified lines | ||
| 2399 | 2427 | return ret; |
| 2400 | 2428 | } |
| 2401 | 2429 | |
| 2430 | + ret = ov5670_mipi_configure(ov5670); | |
| 2431 | + if (ret) { | |
| 2432 | + dev_err(&client->dev, "%s failed to configure MIPI\n", __func__); | |
| 2433 | + return ret; | |
| 2434 | + } | |
| 2435 | + | |
| 2402 | 2436 | ret = __v4l2_ctrl_handler_setup(ov5670->sd.ctrl_handler); |
| 2403 | 2437 | if (ret) |
| 2404 | 2438 | return ret; |
| @@ -2647,23 +2681,20 @@ static int ov5670_gpio_probe(struct ov5670 *ov5670) · 242 unmodified lines | ||
| 2647 | 2681 | |
| 2648 | 2682 | static int ov5670_probe(struct i2c_client *client) |
| 2649 | 2683 | { |
| 2684 | + struct fwnode_handle *handle; | |
| 2650 | 2685 | struct ov5670 *ov5670; |
| 2651 | − const char *err_msg; | |
| 2652 | 2686 | u32 input_clk = 0; |
| 2653 | 2687 | bool full_power; |
| 2654 | 2688 | int ret; |
| 2655 | 2689 | |
| 2656 | 2690 | ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL); |
| 2657 | − if (!ov5670) { | |
| 2658 | − ret = -ENOMEM; | |
| 2659 | − err_msg = "devm_kzalloc() error"; | |
| 2660 | − goto error_print; | |
| 2661 | − } | |
| 2691 | + if (!ov5670) | |
| 2692 | + return -ENOMEM; | |
| 2662 | 2693 | |
| 2663 | − ov5670->xvclk = devm_clk_get(&client->dev, NULL); | |
| 2694 | + ov5670->xvclk = devm_clk_get_optional(&client->dev, NULL); | |
| 2664 | 2695 | if (!IS_ERR_OR_NULL(ov5670->xvclk)) |
| 2665 | 2696 | input_clk = clk_get_rate(ov5670->xvclk); |
| 2666 | − else if (PTR_ERR(ov5670->xvclk) == -ENOENT) | |
| 2697 | + else if (!ov5670->xvclk || PTR_ERR(ov5670->xvclk) == -ENOENT) | |
| 2667 | 2698 | device_property_read_u32(&client->dev, "clock-frequency", |
| 2668 | 2699 | &input_clk); |
| 2669 | 2700 | else |
| @@ -2680,29 +2711,38 @@ static int ov5670_probe(struct i2c_client *client) · 10 unmodified lines | ||
| 2680 | 2711 | v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops); |
| 2681 | 2712 | |
| 2682 | 2713 | ret = ov5670_regulators_probe(ov5670); |
| 2683 | − if (ret) { | |
| 2684 | − err_msg = "Regulators probe failed"; | |
| 2685 | − goto error_print; | |
| 2686 | − } | |
| 2714 | + if (ret) | |
| 2715 | + return dev_err_probe(&client->dev, ret, "Regulators probe failed\n"); | |
| 2687 | 2716 | |
| 2688 | 2717 | ret = ov5670_gpio_probe(ov5670); |
| 2689 | − if (ret) { | |
| 2690 | − err_msg = "GPIO probe failed"; | |
| 2691 | − goto error_print; | |
| 2692 | − } | |
| 2718 | + if (ret) | |
| 2719 | + return dev_err_probe(&client->dev, ret, "GPIO probe failed\n"); | |
| 2720 | + | |
| 2721 | + /* Graph Endpoint */ | |
| 2722 | + handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); | |
| 2723 | + if (!handle) | |
| 2724 | + return dev_err_probe(&client->dev, -ENXIO, "Endpoint for node get failed\n"); | |
| 2725 | + | |
| 2726 | + ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; | |
| 2727 | + ov5670->endpoint.bus.mipi_csi2.num_data_lanes = 2; | |
| 2728 | + | |
| 2729 | + ret = v4l2_fwnode_endpoint_alloc_parse(handle, &ov5670->endpoint); | |
| 2730 | + fwnode_handle_put(handle); | |
| 2731 | + if (ret) | |
| 2732 | + return dev_err_probe(&client->dev, ret, "Endpoint parse failed\n"); | |
| 2693 | 2733 | |
| 2694 | 2734 | full_power = acpi_dev_state_d0(&client->dev); |
| 2695 | 2735 | if (full_power) { |
| 2696 | 2736 | ret = ov5670_runtime_resume(&client->dev); |
| 2697 | 2737 | if (ret) { |
| 2698 | − err_msg = "Power up failed"; | |
| 2699 | − goto error_print; | |
| 2738 | + dev_err_probe(&client->dev, ret, "Power up failed\n"); | |
| 2739 | + goto error_endpoint; | |
| 2700 | 2740 | } |
| 2701 | 2741 | |
| 2702 | 2742 | /* Check module identity */ |
| 2703 | 2743 | ret = ov5670_identify_module(ov5670); |
| 2704 | 2744 | if (ret) { |
| 2705 | − err_msg = "ov5670_identify_module() error"; | |
| 2745 | + dev_err_probe(&client->dev, ret, "ov5670_identify_module() error\n"); | |
| 2706 | 2746 | goto error_power_off; |
| 2707 | 2747 | } |
| 2708 | 2748 | } |
| @@ -2714,7 +2754,7 @@ static int ov5670_probe(struct i2c_client *client) · 5 unmodified lines | ||
| 2714 | 2754 | |
| 2715 | 2755 | ret = ov5670_init_controls(ov5670); |
| 2716 | 2756 | if (ret) { |
| 2717 | − err_msg = "ov5670_init_controls() error"; | |
| 2757 | + dev_err_probe(&client->dev, ret, "ov5670_init_controls() error\n"); | |
| 2718 | 2758 | goto error_mutex_destroy; |
| 2719 | 2759 | } |
| 2720 | 2760 | |
| @@ -2727,7 +2767,7 @@ static int ov5670_probe(struct i2c_client *client) · 6 unmodified lines | ||
| 2727 | 2767 | ov5670->pad.flags = MEDIA_PAD_FL_SOURCE; |
| 2728 | 2768 | ret = media_entity_pads_init(&ov5670->sd.entity, 1, &ov5670->pad); |
| 2729 | 2769 | if (ret) { |
| 2730 | − err_msg = "media_entity_pads_init() error"; | |
| 2770 | + dev_err_probe(&client->dev, ret, "media_entity_pads_init() error\n"); | |
| 2731 | 2771 | goto error_handler_free; |
| 2732 | 2772 | } |
| 2733 | 2773 | |
| @@ -2741,7 +2781,7 @@ static int ov5670_probe(struct i2c_client *client) · 7 unmodified lines | ||
| 2741 | 2781 | /* Async register for subdev */ |
| 2742 | 2782 | ret = v4l2_async_register_subdev_sensor(&ov5670->sd); |
| 2743 | 2783 | if (ret < 0) { |
| 2744 | − err_msg = "v4l2_async_register_subdev() error"; | |
| 2784 | + dev_err_probe(&client->dev, ret, "v4l2_async_register_subdev() error\n"); | |
| 2745 | 2785 | goto error_pm_disable; |
| 2746 | 2786 | } |
| 2747 | 2787 | |
| @@ -2764,8 +2804,8 @@ error_power_off: · 16 unmodified lines | ||
| 2764 | 2804 | if (full_power) |
| 2765 | 2805 | ov5670_runtime_suspend(&client->dev); |
| 2766 | 2806 | |
| 2767 | −error_print: | |
| 2768 | − dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret); | |
| 2807 | +error_endpoint: | |
| 2808 | + v4l2_fwnode_endpoint_free(&ov5670->endpoint); | |
| 2769 | 2809 | |
| 2770 | 2810 | return ret; |
| 2771 | 2811 | } |
| @@ -2782,6 +2822,8 @@ static void ov5670_remove(struct i2c_client *client) · 10 unmodified lines | ||
| 2782 | 2822 | |
| 2783 | 2823 | pm_runtime_disable(&client->dev); |
| 2784 | 2824 | ov5670_runtime_suspend(&client->dev); |
| 2825 | + | |
| 2826 | + v4l2_fwnode_endpoint_free(&ov5670->endpoint); | |
| 2785 | 2827 | } |
| 2786 | 2828 | |
| 2787 | 2829 | static const struct dev_pm_ops ov5670_pm_ops = { |
| @@ -1894,14 +1894,9 @@ static int ov7670_probe(struct i2c_client *client) · 1893 unmodified lines | ||
| 1894 | 1894 | info->pclk_hb_disable = true; |
| 1895 | 1895 | } |
| 1896 | 1896 | |
| 1897 | − info->clk = devm_clk_get(&client->dev, "xclk"); /* optional */ | |
| 1898 | − if (IS_ERR(info->clk)) { | |
| 1899 | − ret = PTR_ERR(info->clk); | |
| 1900 | − if (ret == -ENOENT) | |
| 1901 | − info->clk = NULL; | |
| 1902 | − else | |
| 1903 | − return ret; | |
| 1904 | − } | |
| 1897 | + info->clk = devm_clk_get_optional(&client->dev, "xclk"); | |
| 1898 | + if (IS_ERR(info->clk)) | |
| 1899 | + return PTR_ERR(info->clk); | |
| 1905 | 1900 | |
| 1906 | 1901 | ret = ov7670_init_gpio(client, info); |
| 1907 | 1902 | if (ret) |
| @@ -1709,46 +1709,6 @@ static int ov8856_identify_module(struct ov8856 *ov8856) · 1708 unmodified lines | ||
| 1709 | 1709 | return -ENXIO; |
| 1710 | 1710 | } |
| 1711 | 1711 | |
| 1712 | − ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, | |
| 1713 | − OV8856_REG_VALUE_08BIT, OV8856_MODE_STREAMING); | |
| 1714 | − if (ret) | |
| 1715 | − return ret; | |
| 1716 | − | |
| 1717 | − ret = ov8856_write_reg(ov8856, OV8856_OTP_MODE_CTRL, | |
| 1718 | − OV8856_REG_VALUE_08BIT, OV8856_OTP_MODE_AUTO); | |
| 1719 | − if (ret) { | |
| 1720 | − dev_err(&client->dev, "failed to set otp mode"); | |
| 1721 | − return ret; | |
| 1722 | − } | |
| 1723 | − | |
| 1724 | − ret = ov8856_write_reg(ov8856, OV8856_OTP_LOAD_CTRL, | |
| 1725 | − OV8856_REG_VALUE_08BIT, | |
| 1726 | − OV8856_OTP_LOAD_CTRL_ENABLE); | |
| 1727 | − if (ret) { | |
| 1728 | − dev_err(&client->dev, "failed to enable load control"); | |
| 1729 | − return ret; | |
| 1730 | − } | |
| 1731 | − | |
| 1732 | − ret = ov8856_read_reg(ov8856, OV8856_MODULE_REVISION, | |
| 1733 | − OV8856_REG_VALUE_08BIT, &val); | |
| 1734 | − if (ret) { | |
| 1735 | − dev_err(&client->dev, "failed to read module revision"); | |
| 1736 | − return ret; | |
| 1737 | − } | |
| 1738 | − | |
| 1739 | − dev_info(&client->dev, "OV8856 revision %x (%s) at address 0x%02x\n", | |
| 1740 | − val, | |
| 1741 | − val == OV8856_2A_MODULE ? "2A" : | |
| 1742 | − val == OV8856_1B_MODULE ? "1B" : "unknown revision", | |
| 1743 | − client->addr); | |
| 1744 | − | |
| 1745 | − ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, | |
| 1746 | − OV8856_REG_VALUE_08BIT, OV8856_MODE_STANDBY); | |
| 1747 | − if (ret) { | |
| 1748 | − dev_err(&client->dev, "failed to exit streaming mode"); | |
| 1749 | − return ret; | |
| 1750 | − } | |
| 1751 | − | |
| 1752 | 1712 | ov8856->identified = true; |
| 1753 | 1713 | |
| 1754 | 1714 | return 0; |
| @@ -1,1652 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor | |
| 4 | − * with embedded SoC ISP. | |
| 5 | − * | |
| 6 | − * Copyright (C) 2011, Samsung Electronics Co., Ltd. | |
| 7 | − * Sylwester Nawrocki <s.nawrocki@samsung.com> | |
| 8 | − * | |
| 9 | − * Based on a driver authored by Dongsoo Nathaniel Kim. | |
| 10 | − * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | |
| 11 | − */ | |
| 12 | − | |
| 13 | −#include <linux/clk.h> | |
| 14 | −#include <linux/delay.h> | |
| 15 | −#include <linux/gpio.h> | |
| 16 | −#include <linux/i2c.h> | |
| 17 | −#include <linux/media.h> | |
| 18 | −#include <linux/module.h> | |
| 19 | −#include <linux/regulator/consumer.h> | |
| 20 | −#include <linux/slab.h> | |
| 21 | − | |
| 22 | −#include <media/media-entity.h> | |
| 23 | −#include <media/v4l2-ctrls.h> | |
| 24 | −#include <media/v4l2-device.h> | |
| 25 | −#include <media/v4l2-subdev.h> | |
| 26 | −#include <media/v4l2-mediabus.h> | |
| 27 | −#include <media/i2c/s5k6aa.h> | |
| 28 | − | |
| 29 | −static int debug; | |
| 30 | −module_param(debug, int, 0644); | |
| 31 | − | |
| 32 | −#define DRIVER_NAME "S5K6AA" | |
| 33 | − | |
| 34 | −/* The token to indicate array termination */ | |
| 35 | −#define S5K6AA_TERM 0xffff | |
| 36 | −#define S5K6AA_OUT_WIDTH_DEF 640 | |
| 37 | −#define S5K6AA_OUT_HEIGHT_DEF 480 | |
| 38 | −#define S5K6AA_WIN_WIDTH_MAX 1280 | |
| 39 | −#define S5K6AA_WIN_HEIGHT_MAX 1024 | |
| 40 | −#define S5K6AA_WIN_WIDTH_MIN 8 | |
| 41 | −#define S5K6AA_WIN_HEIGHT_MIN 8 | |
| 42 | − | |
| 43 | −/* | |
| 44 | − * H/W register Interface (0xD0000000 - 0xD0000FFF) | |
| 45 | − */ | |
| 46 | −#define AHB_MSB_ADDR_PTR 0xfcfc | |
| 47 | −#define GEN_REG_OFFSH 0xd000 | |
| 48 | −#define REG_CMDWR_ADDRH 0x0028 | |
| 49 | −#define REG_CMDWR_ADDRL 0x002a | |
| 50 | −#define REG_CMDRD_ADDRH 0x002c | |
| 51 | −#define REG_CMDRD_ADDRL 0x002e | |
| 52 | −#define REG_CMDBUF0_ADDR 0x0f12 | |
| 53 | −#define REG_CMDBUF1_ADDR 0x0f10 | |
| 54 | − | |
| 55 | −/* | |
| 56 | − * Host S/W Register interface (0x70000000 - 0x70002000) | |
| 57 | − * The value of the two most significant address bytes is 0x7000, | |
| 58 | − * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs. | |
| 59 | − */ | |
| 60 | −#define HOST_SWIF_OFFSH 0x7000 | |
| 61 | − | |
| 62 | −/* Initialization parameters */ | |
| 63 | −/* Master clock frequency in KHz */ | |
| 64 | −#define REG_I_INCLK_FREQ_L 0x01b8 | |
| 65 | −#define REG_I_INCLK_FREQ_H 0x01ba | |
| 66 | −#define MIN_MCLK_FREQ_KHZ 6000U | |
| 67 | −#define MAX_MCLK_FREQ_KHZ 27000U | |
| 68 | −#define REG_I_USE_NPVI_CLOCKS 0x01c6 | |
| 69 | −#define REG_I_USE_NMIPI_CLOCKS 0x01c8 | |
| 70 | − | |
| 71 | −/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */ | |
| 72 | −#define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc) | |
| 73 | −#define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce) | |
| 74 | −#define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0) | |
| 75 | −#define SYS_PLL_OUT_FREQ (48000000 / 4000) | |
| 76 | −#define PCLK_FREQ_MIN (24000000 / 4000) | |
| 77 | −#define PCLK_FREQ_MAX (48000000 / 4000) | |
| 78 | −#define REG_I_INIT_PARAMS_UPDATED 0x01e0 | |
| 79 | −#define REG_I_ERROR_INFO 0x01e2 | |
| 80 | − | |
| 81 | −/* General purpose parameters */ | |
| 82 | −#define REG_USER_BRIGHTNESS 0x01e4 | |
| 83 | −#define REG_USER_CONTRAST 0x01e6 | |
| 84 | −#define REG_USER_SATURATION 0x01e8 | |
| 85 | −#define REG_USER_SHARPBLUR 0x01ea | |
| 86 | − | |
| 87 | −#define REG_G_SPEC_EFFECTS 0x01ee | |
| 88 | −#define REG_G_ENABLE_PREV 0x01f0 | |
| 89 | −#define REG_G_ENABLE_PREV_CHG 0x01f2 | |
| 90 | −#define REG_G_NEW_CFG_SYNC 0x01f8 | |
| 91 | −#define REG_G_PREVZOOM_IN_WIDTH 0x020a | |
| 92 | −#define REG_G_PREVZOOM_IN_HEIGHT 0x020c | |
| 93 | −#define REG_G_PREVZOOM_IN_XOFFS 0x020e | |
| 94 | −#define REG_G_PREVZOOM_IN_YOFFS 0x0210 | |
| 95 | −#define REG_G_INPUTS_CHANGE_REQ 0x021a | |
| 96 | −#define REG_G_ACTIVE_PREV_CFG 0x021c | |
| 97 | −#define REG_G_PREV_CFG_CHG 0x021e | |
| 98 | −#define REG_G_PREV_OPEN_AFTER_CH 0x0220 | |
| 99 | −#define REG_G_PREV_CFG_ERROR 0x0222 | |
| 100 | − | |
| 101 | −/* Preview control section. n = 0...4. */ | |
| 102 | −#define PREG(n, x) ((n) * 0x26 + x) | |
| 103 | −#define REG_P_OUT_WIDTH(n) PREG(n, 0x0242) | |
| 104 | −#define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244) | |
| 105 | −#define REG_P_FMT(n) PREG(n, 0x0246) | |
| 106 | −#define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248) | |
| 107 | −#define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a) | |
| 108 | −#define REG_P_PVI_MASK(n) PREG(n, 0x024c) | |
| 109 | −#define REG_P_CLK_INDEX(n) PREG(n, 0x024e) | |
| 110 | −#define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250) | |
| 111 | −#define FR_RATE_DYNAMIC 0 | |
| 112 | −#define FR_RATE_FIXED 1 | |
| 113 | −#define FR_RATE_FIXED_ACCURATE 2 | |
| 114 | −#define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252) | |
| 115 | −#define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */ | |
| 116 | −#define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */ | |
| 117 | −/* Frame period in 0.1 ms units */ | |
| 118 | −#define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254) | |
| 119 | −#define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256) | |
| 120 | −/* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */ | |
| 121 | −#define US_TO_FR_TIME(__t) ((__t) / 100) | |
| 122 | −#define S5K6AA_MIN_FR_TIME 33300 /* us */ | |
| 123 | −#define S5K6AA_MAX_FR_TIME 650000 /* us */ | |
| 124 | −#define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */ | |
| 125 | −/* The below 5 registers are for "device correction" values */ | |
| 126 | −#define REG_P_COLORTEMP(n) PREG(n, 0x025e) | |
| 127 | −#define REG_P_PREV_MIRROR(n) PREG(n, 0x0262) | |
| 128 | − | |
| 129 | −/* Extended image property controls */ | |
| 130 | −/* Exposure time in 10 us units */ | |
| 131 | −#define REG_SF_USR_EXPOSURE_L 0x03c6 | |
| 132 | −#define REG_SF_USR_EXPOSURE_H 0x03c8 | |
| 133 | −#define REG_SF_USR_EXPOSURE_CHG 0x03ca | |
| 134 | −#define REG_SF_USR_TOT_GAIN 0x03cc | |
| 135 | −#define REG_SF_USR_TOT_GAIN_CHG 0x03ce | |
| 136 | −#define REG_SF_RGAIN 0x03d0 | |
| 137 | −#define REG_SF_RGAIN_CHG 0x03d2 | |
| 138 | −#define REG_SF_GGAIN 0x03d4 | |
| 139 | −#define REG_SF_GGAIN_CHG 0x03d6 | |
| 140 | −#define REG_SF_BGAIN 0x03d8 | |
| 141 | −#define REG_SF_BGAIN_CHG 0x03da | |
| 142 | −#define REG_SF_FLICKER_QUANT 0x03dc | |
| 143 | −#define REG_SF_FLICKER_QUANT_CHG 0x03de | |
| 144 | − | |
| 145 | −/* Output interface (parallel/MIPI) setup */ | |
| 146 | −#define REG_OIF_EN_MIPI_LANES 0x03fa | |
| 147 | −#define REG_OIF_EN_PACKETS 0x03fc | |
| 148 | −#define REG_OIF_CFG_CHG 0x03fe | |
| 149 | − | |
| 150 | −/* Auto-algorithms enable mask */ | |
| 151 | −#define REG_DBG_AUTOALG_EN 0x0400 | |
| 152 | −#define AALG_ALL_EN_MASK (1 << 0) | |
| 153 | −#define AALG_AE_EN_MASK (1 << 1) | |
| 154 | −#define AALG_DIVLEI_EN_MASK (1 << 2) | |
| 155 | −#define AALG_WB_EN_MASK (1 << 3) | |
| 156 | −#define AALG_FLICKER_EN_MASK (1 << 5) | |
| 157 | −#define AALG_FIT_EN_MASK (1 << 6) | |
| 158 | −#define AALG_WRHW_EN_MASK (1 << 7) | |
| 159 | − | |
| 160 | −/* Firmware revision information */ | |
| 161 | −#define REG_FW_APIVER 0x012e | |
| 162 | −#define S5K6AAFX_FW_APIVER 0x0001 | |
| 163 | −#define REG_FW_REVISION 0x0130 | |
| 164 | − | |
| 165 | −/* For now we use only one user configuration register set */ | |
| 166 | −#define S5K6AA_MAX_PRESETS 1 | |
| 167 | − | |
| 168 | −static const char * const s5k6aa_supply_names[] = { | |
| 169 | − "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */ | |
| 170 | − "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */ | |
| 171 | − "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V) | |
| 172 | − or 2.8V (2.6V to 3.0) */ | |
| 173 | − "vddio", /* I/O supply 1.8V (1.65V to 1.95V) | |
| 174 | − or 2.8V (2.5V to 3.1V) */ | |
| 175 | −}; | |
| 176 | −#define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names) | |
| 177 | − | |
| 178 | −enum s5k6aa_gpio_id { | |
| 179 | − STBY, | |
| 180 | − RSET, | |
| 181 | − GPIO_NUM, | |
| 182 | −}; | |
| 183 | − | |
| 184 | −struct s5k6aa_regval { | |
| 185 | − u16 addr; | |
| 186 | − u16 val; | |
| 187 | −}; | |
| 188 | − | |
| 189 | −struct s5k6aa_pixfmt { | |
| 190 | − u32 code; | |
| 191 | − u32 colorspace; | |
| 192 | − /* REG_P_FMT(x) register value */ | |
| 193 | − u16 reg_p_fmt; | |
| 194 | −}; | |
| 195 | − | |
| 196 | −struct s5k6aa_preset { | |
| 197 | − /* output pixel format and resolution */ | |
| 198 | − struct v4l2_mbus_framefmt mbus_fmt; | |
| 199 | − u8 clk_id; | |
| 200 | − u8 index; | |
| 201 | −}; | |
| 202 | − | |
| 203 | −struct s5k6aa_ctrls { | |
| 204 | − struct v4l2_ctrl_handler handler; | |
| 205 | − /* Auto / manual white balance cluster */ | |
| 206 | − struct v4l2_ctrl *awb; | |
| 207 | − struct v4l2_ctrl *gain_red; | |
| 208 | − struct v4l2_ctrl *gain_blue; | |
| 209 | − struct v4l2_ctrl *gain_green; | |
| 210 | − /* Mirror cluster */ | |
| 211 | − struct v4l2_ctrl *hflip; | |
| 212 | − struct v4l2_ctrl *vflip; | |
| 213 | − /* Auto exposure / manual exposure and gain cluster */ | |
| 214 | − struct v4l2_ctrl *auto_exp; | |
| 215 | − struct v4l2_ctrl *exposure; | |
| 216 | − struct v4l2_ctrl *gain; | |
| 217 | −}; | |
| 218 | − | |
| 219 | −struct s5k6aa_interval { | |
| 220 | − u16 reg_fr_time; | |
| 221 | − struct v4l2_fract interval; | |
| 222 | − /* Maximum rectangle for the interval */ | |
| 223 | − struct v4l2_frmsize_discrete size; | |
| 224 | −}; | |
| 225 | − | |
| 226 | −struct s5k6aa { | |
| 227 | − struct v4l2_subdev sd; | |
| 228 | − struct media_pad pad; | |
| 229 | − | |
| 230 | − enum v4l2_mbus_type bus_type; | |
| 231 | − u8 mipi_lanes; | |
| 232 | − | |
| 233 | − int (*s_power)(int enable); | |
| 234 | − struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES]; | |
| 235 | − struct s5k6aa_gpio gpio[GPIO_NUM]; | |
| 236 | − | |
| 237 | − /* external master clock frequency */ | |
| 238 | − unsigned long mclk_frequency; | |
| 239 | − /* ISP internal master clock frequency */ | |
| 240 | − u16 clk_fop; | |
| 241 | − /* output pixel clock frequency range */ | |
| 242 | − u16 pclk_fmin; | |
| 243 | − u16 pclk_fmax; | |
| 244 | − | |
| 245 | − unsigned int inv_hflip:1; | |
| 246 | − unsigned int inv_vflip:1; | |
| 247 | − | |
| 248 | − /* protects the struct members below */ | |
| 249 | − struct mutex lock; | |
| 250 | − | |
| 251 | − /* sensor matrix scan window */ | |
| 252 | − struct v4l2_rect ccd_rect; | |
| 253 | − | |
| 254 | − struct s5k6aa_ctrls ctrls; | |
| 255 | − struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS]; | |
| 256 | − struct s5k6aa_preset *preset; | |
| 257 | − const struct s5k6aa_interval *fiv; | |
| 258 | − | |
| 259 | − unsigned int streaming:1; | |
| 260 | − unsigned int apply_cfg:1; | |
| 261 | − unsigned int apply_crop:1; | |
| 262 | − unsigned int power; | |
| 263 | −}; | |
| 264 | − | |
| 265 | −static struct s5k6aa_regval s5k6aa_analog_config[] = { | |
| 266 | − /* Analog settings */ | |
| 267 | − { 0x112a, 0x0000 }, { 0x1132, 0x0000 }, | |
| 268 | − { 0x113e, 0x0000 }, { 0x115c, 0x0000 }, | |
| 269 | − { 0x1164, 0x0000 }, { 0x1174, 0x0000 }, | |
| 270 | − { 0x1178, 0x0000 }, { 0x077a, 0x0000 }, | |
| 271 | − { 0x077c, 0x0000 }, { 0x077e, 0x0000 }, | |
| 272 | − { 0x0780, 0x0000 }, { 0x0782, 0x0000 }, | |
| 273 | − { 0x0784, 0x0000 }, { 0x0786, 0x0000 }, | |
| 274 | − { 0x0788, 0x0000 }, { 0x07a2, 0x0000 }, | |
| 275 | − { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 }, | |
| 276 | − { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 }, | |
| 277 | − { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 }, | |
| 278 | − { 0x07bc, 0x0004 }, { 0x07be, 0x0005 }, | |
| 279 | − { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 }, | |
| 280 | −}; | |
| 281 | − | |
| 282 | −/* TODO: Add RGB888 and Bayer format */ | |
| 283 | −static const struct s5k6aa_pixfmt s5k6aa_formats[] = { | |
| 284 | − { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 }, | |
| 285 | − /* range 16-240 */ | |
| 286 | − { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 }, | |
| 287 | − { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 }, | |
| 288 | −}; | |
| 289 | − | |
| 290 | −static const struct s5k6aa_interval s5k6aa_intervals[] = { | |
| 291 | − { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */ | |
| 292 | − { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */ | |
| 293 | − { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */ | |
| 294 | − { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */ | |
| 295 | − { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */ | |
| 296 | −}; | |
| 297 | − | |
| 298 | −#define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */ | |
| 299 | − | |
| 300 | −static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) | |
| 301 | −{ | |
| 302 | − return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd; | |
| 303 | −} | |
| 304 | − | |
| 305 | −static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd) | |
| 306 | −{ | |
| 307 | − return container_of(sd, struct s5k6aa, sd); | |
| 308 | −} | |
| 309 | − | |
| 310 | −/* Set initial values for all preview presets */ | |
| 311 | −static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa) | |
| 312 | −{ | |
| 313 | − struct s5k6aa_preset *preset = &s5k6aa->presets[0]; | |
| 314 | − int i; | |
| 315 | − | |
| 316 | − for (i = 0; i < S5K6AA_MAX_PRESETS; i++) { | |
| 317 | − preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF; | |
| 318 | − preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF; | |
| 319 | − preset->mbus_fmt.code = s5k6aa_formats[0].code; | |
| 320 | − preset->index = i; | |
| 321 | − preset->clk_id = 0; | |
| 322 | − preset++; | |
| 323 | − } | |
| 324 | − | |
| 325 | − s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX]; | |
| 326 | − s5k6aa->preset = &s5k6aa->presets[0]; | |
| 327 | −} | |
| 328 | − | |
| 329 | −static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val) | |
| 330 | −{ | |
| 331 | − u8 wbuf[2] = {addr >> 8, addr & 0xFF}; | |
| 332 | − struct i2c_msg msg[2]; | |
| 333 | − u8 rbuf[2]; | |
| 334 | − int ret; | |
| 335 | − | |
| 336 | − msg[0].addr = client->addr; | |
| 337 | − msg[0].flags = 0; | |
| 338 | − msg[0].len = 2; | |
| 339 | − msg[0].buf = wbuf; | |
| 340 | − | |
| 341 | − msg[1].addr = client->addr; | |
| 342 | − msg[1].flags = I2C_M_RD; | |
| 343 | − msg[1].len = 2; | |
| 344 | − msg[1].buf = rbuf; | |
| 345 | − | |
| 346 | − ret = i2c_transfer(client->adapter, msg, 2); | |
| 347 | − *val = be16_to_cpu(*((__be16 *)rbuf)); | |
| 348 | − | |
| 349 | − v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); | |
| 350 | − | |
| 351 | − return ret == 2 ? 0 : ret; | |
| 352 | −} | |
| 353 | − | |
| 354 | −static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val) | |
| 355 | −{ | |
| 356 | − u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF}; | |
| 357 | − | |
| 358 | − int ret = i2c_master_send(client, buf, 4); | |
| 359 | − v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val); | |
| 360 | − | |
| 361 | − return ret == 4 ? 0 : ret; | |
| 362 | −} | |
| 363 | − | |
| 364 | −/* The command register write, assumes Command_Wr_addH = 0x7000. */ | |
| 365 | −static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val) | |
| 366 | −{ | |
| 367 | − int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr); | |
| 368 | − if (ret) | |
| 369 | − return ret; | |
| 370 | − return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val); | |
| 371 | −} | |
| 372 | − | |
| 373 | −/* The command register read, assumes Command_Rd_addH = 0x7000. */ | |
| 374 | −static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val) | |
| 375 | −{ | |
| 376 | − int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr); | |
| 377 | − if (ret) | |
| 378 | − return ret; | |
| 379 | − return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val); | |
| 380 | −} | |
| 381 | − | |
| 382 | −static int s5k6aa_write_array(struct v4l2_subdev *sd, | |
| 383 | − const struct s5k6aa_regval *msg) | |
| 384 | −{ | |
| 385 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 386 | − u16 addr_incr = 0; | |
| 387 | − int ret = 0; | |
| 388 | − | |
| 389 | − while (msg->addr != S5K6AA_TERM) { | |
| 390 | − if (addr_incr != 2) | |
| 391 | − ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL, | |
| 392 | − msg->addr); | |
| 393 | − if (ret) | |
| 394 | − break; | |
| 395 | − ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val); | |
| 396 | − if (ret) | |
| 397 | − break; | |
| 398 | − /* Assume that msg->addr is always less than 0xfffc */ | |
| 399 | − addr_incr = (msg + 1)->addr - msg->addr; | |
| 400 | − msg++; | |
| 401 | − } | |
| 402 | − | |
| 403 | − return ret; | |
| 404 | −} | |
| 405 | − | |
| 406 | −/* Configure the AHB high address bytes for GTG registers access */ | |
| 407 | −static int s5k6aa_set_ahb_address(struct i2c_client *client) | |
| 408 | −{ | |
| 409 | − int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH); | |
| 410 | − if (ret) | |
| 411 | − return ret; | |
| 412 | − ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH); | |
| 413 | − if (ret) | |
| 414 | − return ret; | |
| 415 | − return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH); | |
| 416 | −} | |
| 417 | − | |
| 418 | −/** | |
| 419 | − * s5k6aa_configure_pixel_clocks - apply ISP main clock/PLL configuration | |
| 420 | − * @s5k6aa: pointer to &struct s5k6aa describing the device | |
| 421 | − * | |
| 422 | − * Configure the internal ISP PLL for the required output frequency. | |
| 423 | − * Locking: called with s5k6aa.lock mutex held. | |
| 424 | − */ | |
| 425 | −static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa) | |
| 426 | −{ | |
| 427 | − struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 428 | − unsigned long fmclk = s5k6aa->mclk_frequency / 1000; | |
| 429 | − u16 status; | |
| 430 | − int ret; | |
| 431 | − | |
| 432 | − if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ, | |
| 433 | − "Invalid clock frequency: %ld\n", fmclk)) | |
| 434 | − return -EINVAL; | |
| 435 | − | |
| 436 | − s5k6aa->pclk_fmin = PCLK_FREQ_MIN; | |
| 437 | − s5k6aa->pclk_fmax = PCLK_FREQ_MAX; | |
| 438 | − s5k6aa->clk_fop = SYS_PLL_OUT_FREQ; | |
| 439 | − | |
| 440 | − /* External input clock frequency in kHz */ | |
| 441 | − ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16); | |
| 442 | − if (!ret) | |
| 443 | − ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF); | |
| 444 | − if (!ret) | |
| 445 | − ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1); | |
| 446 | − /* Internal PLL frequency */ | |
| 447 | − if (!ret) | |
| 448 | − ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop); | |
| 449 | − if (!ret) | |
| 450 | − ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0), | |
| 451 | − s5k6aa->pclk_fmin); | |
| 452 | − if (!ret) | |
| 453 | − ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0), | |
| 454 | − s5k6aa->pclk_fmax); | |
| 455 | − if (!ret) | |
| 456 | − ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1); | |
| 457 | − if (!ret) | |
| 458 | − ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status); | |
| 459 | − | |
| 460 | − return ret ? ret : (status ? -EINVAL : 0); | |
| 461 | −} | |
| 462 | − | |
| 463 | −/* Set horizontal and vertical image flipping */ | |
| 464 | −static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip) | |
| 465 | −{ | |
| 466 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 467 | − int index = s5k6aa->preset->index; | |
| 468 | − | |
| 469 | − unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip; | |
| 470 | − unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1); | |
| 471 | − | |
| 472 | − return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip); | |
| 473 | −} | |
| 474 | − | |
| 475 | −/* Configure auto/manual white balance and R/G/B gains */ | |
| 476 | −static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb) | |
| 477 | −{ | |
| 478 | − struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 479 | − struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; | |
| 480 | − u16 reg; | |
| 481 | − | |
| 482 | − int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, ®); | |
| 483 | − | |
| 484 | − if (!ret && !awb) { | |
| 485 | − ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val); | |
| 486 | − if (!ret) | |
| 487 | − ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1); | |
| 488 | − if (ret) | |
| 489 | − return ret; | |
| 490 | − | |
| 491 | − ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val); | |
| 492 | − if (!ret) | |
| 493 | − ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1); | |
| 494 | − if (ret) | |
| 495 | − return ret; | |
| 496 | − | |
| 497 | − ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val); | |
| 498 | − if (!ret) | |
| 499 | − ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1); | |
| 500 | − } | |
| 501 | − if (!ret) { | |
| 502 | − reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK; | |
| 503 | − ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg); | |
| 504 | − } | |
| 505 | − | |
| 506 | − return ret; | |
| 507 | −} | |
| 508 | − | |
| 509 | −/* Program FW with exposure time, 'exposure' in us units */ | |
| 510 | −static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure) | |
| 511 | −{ | |
| 512 | − unsigned int time = exposure / 10; | |
| 513 | − | |
| 514 | − int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff); | |
| 515 | − if (!ret) | |
| 516 | − ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16); | |
| 517 | − if (ret) | |
| 518 | − return ret; | |
| 519 | − return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1); | |
| 520 | −} | |
| 521 | − | |
| 522 | −static int s5k6aa_set_user_gain(struct i2c_client *client, int gain) | |
| 523 | −{ | |
| 524 | − int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain); | |
| 525 | − if (ret) | |
| 526 | − return ret; | |
| 527 | − return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1); | |
| 528 | −} | |
| 529 | − | |
| 530 | −/* Set auto/manual exposure and total gain */ | |
| 531 | −static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value) | |
| 532 | −{ | |
| 533 | − struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 534 | − unsigned int exp_time = s5k6aa->ctrls.exposure->val; | |
| 535 | − u16 auto_alg; | |
| 536 | − | |
| 537 | − int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg); | |
| 538 | − if (ret) | |
| 539 | − return ret; | |
| 540 | − | |
| 541 | − v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n", | |
| 542 | − exp_time, value, auto_alg); | |
| 543 | − | |
| 544 | − if (value == V4L2_EXPOSURE_AUTO) { | |
| 545 | − auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK; | |
| 546 | − } else { | |
| 547 | − ret = s5k6aa_set_user_exposure(c, exp_time); | |
| 548 | − if (ret) | |
| 549 | − return ret; | |
| 550 | − ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val); | |
| 551 | − if (ret) | |
| 552 | − return ret; | |
| 553 | − auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK); | |
| 554 | − } | |
| 555 | − | |
| 556 | − return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg); | |
| 557 | −} | |
| 558 | − | |
| 559 | −static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value) | |
| 560 | −{ | |
| 561 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 562 | − u16 auto_alg; | |
| 563 | − int ret; | |
| 564 | − | |
| 565 | − ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg); | |
| 566 | − if (ret) | |
| 567 | − return ret; | |
| 568 | − | |
| 569 | − if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) { | |
| 570 | − auto_alg |= AALG_FLICKER_EN_MASK; | |
| 571 | − } else { | |
| 572 | − auto_alg &= ~AALG_FLICKER_EN_MASK; | |
| 573 | − /* The V4L2_CID_LINE_FREQUENCY control values match | |
| 574 | − * the register values */ | |
| 575 | − ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value); | |
| 576 | − if (ret) | |
| 577 | − return ret; | |
| 578 | − ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1); | |
| 579 | − if (ret) | |
| 580 | − return ret; | |
| 581 | − } | |
| 582 | − | |
| 583 | − return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg); | |
| 584 | −} | |
| 585 | − | |
| 586 | −static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val) | |
| 587 | −{ | |
| 588 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 589 | − static const struct v4l2_control colorfx[] = { | |
| 590 | − { V4L2_COLORFX_NONE, 0 }, | |
| 591 | − { V4L2_COLORFX_BW, 1 }, | |
| 592 | − { V4L2_COLORFX_NEGATIVE, 2 }, | |
| 593 | − { V4L2_COLORFX_SEPIA, 3 }, | |
| 594 | − { V4L2_COLORFX_SKY_BLUE, 4 }, | |
| 595 | − { V4L2_COLORFX_SKETCH, 5 }, | |
| 596 | − }; | |
| 597 | − int i; | |
| 598 | − | |
| 599 | − for (i = 0; i < ARRAY_SIZE(colorfx); i++) { | |
| 600 | − if (colorfx[i].id == val) | |
| 601 | − return s5k6aa_write(client, REG_G_SPEC_EFFECTS, | |
| 602 | − colorfx[i].value); | |
| 603 | − } | |
| 604 | − return -EINVAL; | |
| 605 | −} | |
| 606 | − | |
| 607 | −static int s5k6aa_preview_config_status(struct i2c_client *client) | |
| 608 | −{ | |
| 609 | − u16 error = 0; | |
| 610 | − int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error); | |
| 611 | − | |
| 612 | − v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret); | |
| 613 | − return ret ? ret : (error ? -EINVAL : 0); | |
| 614 | −} | |
| 615 | − | |
| 616 | −static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa, | |
| 617 | − struct v4l2_mbus_framefmt *mf) | |
| 618 | −{ | |
| 619 | − unsigned int i; | |
| 620 | − | |
| 621 | − for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++) | |
| 622 | − if (mf->colorspace == s5k6aa_formats[i].colorspace && | |
| 623 | − mf->code == s5k6aa_formats[i].code) | |
| 624 | − return i; | |
| 625 | − return 0; | |
| 626 | −} | |
| 627 | − | |
| 628 | −static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa, | |
| 629 | − struct s5k6aa_preset *preset) | |
| 630 | −{ | |
| 631 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 632 | − int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt); | |
| 633 | − int ret; | |
| 634 | − | |
| 635 | − ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index), | |
| 636 | − preset->mbus_fmt.width); | |
| 637 | − if (!ret) | |
| 638 | − ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index), | |
| 639 | − preset->mbus_fmt.height); | |
| 640 | − if (!ret) | |
| 641 | − ret = s5k6aa_write(client, REG_P_FMT(preset->index), | |
| 642 | − s5k6aa_formats[fmt_index].reg_p_fmt); | |
| 643 | − return ret; | |
| 644 | −} | |
| 645 | − | |
| 646 | −static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa) | |
| 647 | −{ | |
| 648 | − struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 649 | − struct v4l2_rect *r = &s5k6aa->ccd_rect; | |
| 650 | − int ret; | |
| 651 | − | |
| 652 | − ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width); | |
| 653 | − if (!ret) | |
| 654 | − ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height); | |
| 655 | − if (!ret) | |
| 656 | − ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left); | |
| 657 | − if (!ret) | |
| 658 | − ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top); | |
| 659 | − if (!ret) | |
| 660 | − ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1); | |
| 661 | − if (!ret) | |
| 662 | − s5k6aa->apply_crop = 0; | |
| 663 | − | |
| 664 | − return ret; | |
| 665 | −} | |
| 666 | − | |
| 667 | −/** | |
| 668 | − * s5k6aa_configure_video_bus - configure the video output interface | |
| 669 | − * @s5k6aa: pointer to &struct s5k6aa describing the device | |
| 670 | − * @bus_type: video bus type: parallel or MIPI-CSI | |
| 671 | − * @nlanes: number of MIPI lanes to be used (MIPI-CSI only) | |
| 672 | − * | |
| 673 | − * Note: Only parallel bus operation has been tested. | |
| 674 | − */ | |
| 675 | −static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa, | |
| 676 | − enum v4l2_mbus_type bus_type, int nlanes) | |
| 677 | −{ | |
| 678 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 679 | − u16 cfg = 0; | |
| 680 | − int ret; | |
| 681 | − | |
| 682 | − /* | |
| 683 | − * TODO: The sensor is supposed to support BT.601 and BT.656 | |
| 684 | − * but there is nothing indicating how to switch between both | |
| 685 | − * in the datasheet. For now default BT.601 interface is assumed. | |
| 686 | − */ | |
| 687 | − if (bus_type == V4L2_MBUS_CSI2_DPHY) | |
| 688 | − cfg = nlanes; | |
| 689 | − else if (bus_type != V4L2_MBUS_PARALLEL) | |
| 690 | − return -EINVAL; | |
| 691 | − | |
| 692 | − ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg); | |
| 693 | − if (ret) | |
| 694 | − return ret; | |
| 695 | − return s5k6aa_write(client, REG_OIF_CFG_CHG, 1); | |
| 696 | −} | |
| 697 | − | |
| 698 | −/* This function should be called when switching to new user configuration set*/ | |
| 699 | −static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout, | |
| 700 | − int cid) | |
| 701 | −{ | |
| 702 | − unsigned long end = jiffies + msecs_to_jiffies(timeout); | |
| 703 | − u16 reg = 1; | |
| 704 | − int ret; | |
| 705 | − | |
| 706 | − ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid); | |
| 707 | − if (!ret) | |
| 708 | − ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | |
| 709 | − if (!ret) | |
| 710 | − ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1); | |
| 711 | − if (timeout == 0) | |
| 712 | − return ret; | |
| 713 | − | |
| 714 | − while (ret >= 0 && time_is_after_jiffies(end)) { | |
| 715 | − ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, ®); | |
| 716 | − if (!reg) | |
| 717 | − return 0; | |
| 718 | − usleep_range(1000, 5000); | |
| 719 | − } | |
| 720 | − return ret ? ret : -ETIMEDOUT; | |
| 721 | −} | |
| 722 | − | |
| 723 | −/** | |
| 724 | − * s5k6aa_set_prev_config - write user preview register set | |
| 725 | − * @s5k6aa: pointer to &struct s5k6aa describing the device | |
| 726 | − * @preset: s5kaa preset to be applied | |
| 727 | − * | |
| 728 | − * Configure output resolution and color format, pixel clock | |
| 729 | − * frequency range, device frame rate type and frame period range. | |
| 730 | − */ | |
| 731 | −static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa, | |
| 732 | − struct s5k6aa_preset *preset) | |
| 733 | −{ | |
| 734 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 735 | − int idx = preset->index; | |
| 736 | − u16 frame_rate_q; | |
| 737 | − int ret; | |
| 738 | − | |
| 739 | − if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME) | |
| 740 | − frame_rate_q = FR_RATE_Q_BEST_FRRATE; | |
| 741 | − else | |
| 742 | − frame_rate_q = FR_RATE_Q_BEST_QUALITY; | |
| 743 | − | |
| 744 | − ret = s5k6aa_set_output_framefmt(s5k6aa, preset); | |
| 745 | − if (!ret) | |
| 746 | − ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx), | |
| 747 | − s5k6aa->pclk_fmax); | |
| 748 | − if (!ret) | |
| 749 | − ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx), | |
| 750 | − s5k6aa->pclk_fmin); | |
| 751 | − if (!ret) | |
| 752 | − ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx), | |
| 753 | − preset->clk_id); | |
| 754 | − if (!ret) | |
| 755 | − ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx), | |
| 756 | − FR_RATE_DYNAMIC); | |
| 757 | − if (!ret) | |
| 758 | − ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx), | |
| 759 | − frame_rate_q); | |
| 760 | − if (!ret) | |
| 761 | − ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx), | |
| 762 | − s5k6aa->fiv->reg_fr_time + 33); | |
| 763 | − if (!ret) | |
| 764 | − ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx), | |
| 765 | − s5k6aa->fiv->reg_fr_time - 33); | |
| 766 | − if (!ret) | |
| 767 | − ret = s5k6aa_new_config_sync(client, 250, idx); | |
| 768 | − if (!ret) | |
| 769 | − ret = s5k6aa_preview_config_status(client); | |
| 770 | − if (!ret) | |
| 771 | − s5k6aa->apply_cfg = 0; | |
| 772 | − | |
| 773 | − v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n", | |
| 774 | − s5k6aa->fiv->reg_fr_time, ret); | |
| 775 | − return ret; | |
| 776 | −} | |
| 777 | − | |
| 778 | −/** | |
| 779 | − * s5k6aa_initialize_isp - basic ISP MCU initialization | |
| 780 | − * @sd: pointer to V4L2 sub-device descriptor | |
| 781 | − * | |
| 782 | − * Configure AHB addresses for registers read/write; configure PLLs for | |
| 783 | − * required output pixel clock. The ISP power supply needs to be already | |
| 784 | − * enabled, with an optional H/W reset. | |
| 785 | − * Locking: called with s5k6aa.lock mutex held. | |
| 786 | − */ | |
| 787 | −static int s5k6aa_initialize_isp(struct v4l2_subdev *sd) | |
| 788 | −{ | |
| 789 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 790 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 791 | − int ret; | |
| 792 | − | |
| 793 | − s5k6aa->apply_crop = 1; | |
| 794 | − s5k6aa->apply_cfg = 1; | |
| 795 | − msleep(100); | |
| 796 | − | |
| 797 | − ret = s5k6aa_set_ahb_address(client); | |
| 798 | − if (ret) | |
| 799 | − return ret; | |
| 800 | − ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type, | |
| 801 | − s5k6aa->mipi_lanes); | |
| 802 | − if (ret) | |
| 803 | − return ret; | |
| 804 | − ret = s5k6aa_write_array(sd, s5k6aa_analog_config); | |
| 805 | − if (ret) | |
| 806 | − return ret; | |
| 807 | − msleep(20); | |
| 808 | − | |
| 809 | − return s5k6aa_configure_pixel_clocks(s5k6aa); | |
| 810 | −} | |
| 811 | − | |
| 812 | −static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val) | |
| 813 | −{ | |
| 814 | − if (!gpio_is_valid(priv->gpio[id].gpio)) | |
| 815 | − return 0; | |
| 816 | − gpio_set_value(priv->gpio[id].gpio, !!val); | |
| 817 | − return 1; | |
| 818 | −} | |
| 819 | − | |
| 820 | −static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id) | |
| 821 | −{ | |
| 822 | − return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level); | |
| 823 | −} | |
| 824 | − | |
| 825 | −static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id) | |
| 826 | −{ | |
| 827 | − return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level); | |
| 828 | −} | |
| 829 | − | |
| 830 | −static int __s5k6aa_power_on(struct s5k6aa *s5k6aa) | |
| 831 | −{ | |
| 832 | − int ret; | |
| 833 | − | |
| 834 | − ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | |
| 835 | − if (ret) | |
| 836 | − return ret; | |
| 837 | − if (s5k6aa_gpio_deassert(s5k6aa, STBY)) | |
| 838 | − usleep_range(150, 200); | |
| 839 | − | |
| 840 | − if (s5k6aa->s_power) | |
| 841 | − ret = s5k6aa->s_power(1); | |
| 842 | − usleep_range(4000, 5000); | |
| 843 | − | |
| 844 | − if (s5k6aa_gpio_deassert(s5k6aa, RSET)) | |
| 845 | − msleep(20); | |
| 846 | − | |
| 847 | − return ret; | |
| 848 | −} | |
| 849 | − | |
| 850 | −static int __s5k6aa_power_off(struct s5k6aa *s5k6aa) | |
| 851 | −{ | |
| 852 | − int ret; | |
| 853 | − | |
| 854 | − if (s5k6aa_gpio_assert(s5k6aa, RSET)) | |
| 855 | − usleep_range(100, 150); | |
| 856 | − | |
| 857 | − if (s5k6aa->s_power) { | |
| 858 | − ret = s5k6aa->s_power(0); | |
| 859 | − if (ret) | |
| 860 | − return ret; | |
| 861 | − } | |
| 862 | − if (s5k6aa_gpio_assert(s5k6aa, STBY)) | |
| 863 | − usleep_range(50, 100); | |
| 864 | − s5k6aa->streaming = 0; | |
| 865 | − | |
| 866 | − return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | |
| 867 | −} | |
| 868 | − | |
| 869 | −/* | |
| 870 | − * V4L2 subdev core and video operations | |
| 871 | − */ | |
| 872 | −static int s5k6aa_set_power(struct v4l2_subdev *sd, int on) | |
| 873 | −{ | |
| 874 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 875 | − int ret = 0; | |
| 876 | − | |
| 877 | − mutex_lock(&s5k6aa->lock); | |
| 878 | − | |
| 879 | − if (s5k6aa->power == !on) { | |
| 880 | − if (on) { | |
| 881 | − ret = __s5k6aa_power_on(s5k6aa); | |
| 882 | − if (!ret) | |
| 883 | − ret = s5k6aa_initialize_isp(sd); | |
| 884 | − } else { | |
| 885 | − ret = __s5k6aa_power_off(s5k6aa); | |
| 886 | − } | |
| 887 | − | |
| 888 | − if (!ret) | |
| 889 | − s5k6aa->power += on ? 1 : -1; | |
| 890 | − } | |
| 891 | − | |
| 892 | − mutex_unlock(&s5k6aa->lock); | |
| 893 | − | |
| 894 | − if (!on || ret || s5k6aa->power != 1) | |
| 895 | − return ret; | |
| 896 | − | |
| 897 | − return v4l2_ctrl_handler_setup(sd->ctrl_handler); | |
| 898 | −} | |
| 899 | − | |
| 900 | −static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable) | |
| 901 | −{ | |
| 902 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 903 | − int ret = 0; | |
| 904 | − | |
| 905 | − ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable); | |
| 906 | − if (!ret) | |
| 907 | − ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1); | |
| 908 | − if (!ret) | |
| 909 | − s5k6aa->streaming = enable; | |
| 910 | − | |
| 911 | − return ret; | |
| 912 | −} | |
| 913 | − | |
| 914 | −static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on) | |
| 915 | −{ | |
| 916 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 917 | − int ret = 0; | |
| 918 | − | |
| 919 | − mutex_lock(&s5k6aa->lock); | |
| 920 | − | |
| 921 | − if (s5k6aa->streaming == !on) { | |
| 922 | − if (!ret && s5k6aa->apply_cfg) | |
| 923 | − ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset); | |
| 924 | − if (s5k6aa->apply_crop) | |
| 925 | − ret = s5k6aa_set_input_params(s5k6aa); | |
| 926 | − if (!ret) | |
| 927 | − ret = __s5k6aa_stream(s5k6aa, !!on); | |
| 928 | − } | |
| 929 | − mutex_unlock(&s5k6aa->lock); | |
| 930 | − | |
| 931 | − return ret; | |
| 932 | −} | |
| 933 | − | |
| 934 | −static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd, | |
| 935 | − struct v4l2_subdev_frame_interval *fi) | |
| 936 | −{ | |
| 937 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 938 | − | |
| 939 | − mutex_lock(&s5k6aa->lock); | |
| 940 | − fi->interval = s5k6aa->fiv->interval; | |
| 941 | − mutex_unlock(&s5k6aa->lock); | |
| 942 | − | |
| 943 | − return 0; | |
| 944 | −} | |
| 945 | − | |
| 946 | −static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa, | |
| 947 | − struct v4l2_subdev_frame_interval *fi) | |
| 948 | −{ | |
| 949 | − struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt; | |
| 950 | − const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0]; | |
| 951 | − unsigned int err, min_err = UINT_MAX; | |
| 952 | − unsigned int i, fr_time; | |
| 953 | − | |
| 954 | − if (fi->interval.denominator == 0) | |
| 955 | − return -EINVAL; | |
| 956 | − | |
| 957 | − fr_time = fi->interval.numerator * 10000 / fi->interval.denominator; | |
| 958 | − | |
| 959 | − for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) { | |
| 960 | − const struct s5k6aa_interval *iv = &s5k6aa_intervals[i]; | |
| 961 | − | |
| 962 | − if (mbus_fmt->width > iv->size.width || | |
| 963 | − mbus_fmt->height > iv->size.height) | |
| 964 | − continue; | |
| 965 | − | |
| 966 | − err = abs(iv->reg_fr_time - fr_time); | |
| 967 | − if (err < min_err) { | |
| 968 | − fiv = iv; | |
| 969 | − min_err = err; | |
| 970 | − } | |
| 971 | − } | |
| 972 | − s5k6aa->fiv = fiv; | |
| 973 | − | |
| 974 | − v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n", | |
| 975 | − fiv->reg_fr_time * 100); | |
| 976 | − return 0; | |
| 977 | −} | |
| 978 | − | |
| 979 | −static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd, | |
| 980 | − struct v4l2_subdev_frame_interval *fi) | |
| 981 | −{ | |
| 982 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 983 | − int ret; | |
| 984 | − | |
| 985 | − v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n", | |
| 986 | − fi->interval.numerator, fi->interval.denominator); | |
| 987 | − | |
| 988 | − mutex_lock(&s5k6aa->lock); | |
| 989 | − ret = __s5k6aa_set_frame_interval(s5k6aa, fi); | |
| 990 | − s5k6aa->apply_cfg = 1; | |
| 991 | − | |
| 992 | − mutex_unlock(&s5k6aa->lock); | |
| 993 | − return ret; | |
| 994 | −} | |
| 995 | − | |
| 996 | −/* | |
| 997 | − * V4L2 subdev pad level and video operations | |
| 998 | − */ | |
| 999 | −static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, | |
| 1000 | − struct v4l2_subdev_state *sd_state, | |
| 1001 | − struct v4l2_subdev_frame_interval_enum *fie) | |
| 1002 | −{ | |
| 1003 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 1004 | − const struct s5k6aa_interval *fi; | |
| 1005 | − int ret = 0; | |
| 1006 | − | |
| 1007 | − if (fie->index >= ARRAY_SIZE(s5k6aa_intervals)) | |
| 1008 | − return -EINVAL; | |
| 1009 | − | |
| 1010 | − v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN, | |
| 1011 | − S5K6AA_WIN_WIDTH_MAX, 1, | |
| 1012 | − &fie->height, S5K6AA_WIN_HEIGHT_MIN, | |
| 1013 | − S5K6AA_WIN_HEIGHT_MAX, 1, 0); | |
| 1014 | − | |
| 1015 | − mutex_lock(&s5k6aa->lock); | |
| 1016 | − fi = &s5k6aa_intervals[fie->index]; | |
| 1017 | − if (fie->width > fi->size.width || fie->height > fi->size.height) | |
| 1018 | − ret = -EINVAL; | |
| 1019 | − else | |
| 1020 | − fie->interval = fi->interval; | |
| 1021 | − mutex_unlock(&s5k6aa->lock); | |
| 1022 | − | |
| 1023 | − return ret; | |
| 1024 | −} | |
| 1025 | − | |
| 1026 | −static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, | |
| 1027 | − struct v4l2_subdev_state *sd_state, | |
| 1028 | − struct v4l2_subdev_mbus_code_enum *code) | |
| 1029 | −{ | |
| 1030 | − if (code->index >= ARRAY_SIZE(s5k6aa_formats)) | |
| 1031 | − return -EINVAL; | |
| 1032 | − | |
| 1033 | − code->code = s5k6aa_formats[code->index].code; | |
| 1034 | − return 0; | |
| 1035 | −} | |
| 1036 | − | |
| 1037 | −static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, | |
| 1038 | − struct v4l2_subdev_state *sd_state, | |
| 1039 | − struct v4l2_subdev_frame_size_enum *fse) | |
| 1040 | −{ | |
| 1041 | − int i = ARRAY_SIZE(s5k6aa_formats); | |
| 1042 | − | |
| 1043 | − if (fse->index > 0) | |
| 1044 | − return -EINVAL; | |
| 1045 | − | |
| 1046 | − while (--i) | |
| 1047 | − if (fse->code == s5k6aa_formats[i].code) | |
| 1048 | − break; | |
| 1049 | − | |
| 1050 | − fse->code = s5k6aa_formats[i].code; | |
| 1051 | − fse->min_width = S5K6AA_WIN_WIDTH_MIN; | |
| 1052 | − fse->max_width = S5K6AA_WIN_WIDTH_MAX; | |
| 1053 | − fse->max_height = S5K6AA_WIN_HEIGHT_MIN; | |
| 1054 | − fse->min_height = S5K6AA_WIN_HEIGHT_MAX; | |
| 1055 | − | |
| 1056 | − return 0; | |
| 1057 | −} | |
| 1058 | − | |
| 1059 | −static struct v4l2_rect * | |
| 1060 | −__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, | |
| 1061 | − struct v4l2_subdev_state *sd_state, | |
| 1062 | − enum v4l2_subdev_format_whence which) | |
| 1063 | −{ | |
| 1064 | − if (which == V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 1065 | − return &s5k6aa->ccd_rect; | |
| 1066 | − | |
| 1067 | − WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY); | |
| 1068 | − return v4l2_subdev_get_try_crop(&s5k6aa->sd, sd_state, 0); | |
| 1069 | −} | |
| 1070 | − | |
| 1071 | −static void s5k6aa_try_format(struct s5k6aa *s5k6aa, | |
| 1072 | − struct v4l2_mbus_framefmt *mf) | |
| 1073 | −{ | |
| 1074 | − unsigned int index; | |
| 1075 | − | |
| 1076 | − v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN, | |
| 1077 | − S5K6AA_WIN_WIDTH_MAX, 1, | |
| 1078 | − &mf->height, S5K6AA_WIN_HEIGHT_MIN, | |
| 1079 | − S5K6AA_WIN_HEIGHT_MAX, 1, 0); | |
| 1080 | − | |
| 1081 | − if (mf->colorspace != V4L2_COLORSPACE_JPEG && | |
| 1082 | − mf->colorspace != V4L2_COLORSPACE_REC709) | |
| 1083 | − mf->colorspace = V4L2_COLORSPACE_JPEG; | |
| 1084 | − | |
| 1085 | − index = s5k6aa_get_pixfmt_index(s5k6aa, mf); | |
| 1086 | − | |
| 1087 | − mf->colorspace = s5k6aa_formats[index].colorspace; | |
| 1088 | − mf->code = s5k6aa_formats[index].code; | |
| 1089 | − mf->field = V4L2_FIELD_NONE; | |
| 1090 | −} | |
| 1091 | − | |
| 1092 | −static int s5k6aa_get_fmt(struct v4l2_subdev *sd, | |
| 1093 | − struct v4l2_subdev_state *sd_state, | |
| 1094 | − struct v4l2_subdev_format *fmt) | |
| 1095 | −{ | |
| 1096 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 1097 | − struct v4l2_mbus_framefmt *mf; | |
| 1098 | − | |
| 1099 | − memset(fmt->reserved, 0, sizeof(fmt->reserved)); | |
| 1100 | − | |
| 1101 | − if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
| 1102 | − mf = v4l2_subdev_get_try_format(sd, sd_state, 0); | |
| 1103 | − fmt->format = *mf; | |
| 1104 | − return 0; | |
| 1105 | − } | |
| 1106 | − | |
| 1107 | − mutex_lock(&s5k6aa->lock); | |
| 1108 | − fmt->format = s5k6aa->preset->mbus_fmt; | |
| 1109 | − mutex_unlock(&s5k6aa->lock); | |
| 1110 | − | |
| 1111 | − return 0; | |
| 1112 | −} | |
| 1113 | − | |
| 1114 | −static int s5k6aa_set_fmt(struct v4l2_subdev *sd, | |
| 1115 | − struct v4l2_subdev_state *sd_state, | |
| 1116 | − struct v4l2_subdev_format *fmt) | |
| 1117 | −{ | |
| 1118 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 1119 | − struct s5k6aa_preset *preset = s5k6aa->preset; | |
| 1120 | − struct v4l2_mbus_framefmt *mf; | |
| 1121 | − struct v4l2_rect *crop; | |
| 1122 | − int ret = 0; | |
| 1123 | − | |
| 1124 | − mutex_lock(&s5k6aa->lock); | |
| 1125 | − s5k6aa_try_format(s5k6aa, &fmt->format); | |
| 1126 | − | |
| 1127 | − if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
| 1128 | − mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); | |
| 1129 | − crop = v4l2_subdev_get_try_crop(sd, sd_state, 0); | |
| 1130 | − } else { | |
| 1131 | − if (s5k6aa->streaming) { | |
| 1132 | − ret = -EBUSY; | |
| 1133 | − } else { | |
| 1134 | − mf = &preset->mbus_fmt; | |
| 1135 | − crop = &s5k6aa->ccd_rect; | |
| 1136 | − s5k6aa->apply_cfg = 1; | |
| 1137 | − } | |
| 1138 | − } | |
| 1139 | − | |
| 1140 | − if (ret == 0) { | |
| 1141 | − struct v4l2_subdev_frame_interval fiv = { | |
| 1142 | − .interval = {0, 1} | |
| 1143 | − }; | |
| 1144 | − | |
| 1145 | − *mf = fmt->format; | |
| 1146 | − /* | |
| 1147 | − * Make sure the crop window is valid, i.e. its size is | |
| 1148 | − * greater than the output window, as the ISP supports | |
| 1149 | − * only down-scaling. | |
| 1150 | − */ | |
| 1151 | − crop->width = clamp_t(unsigned int, crop->width, mf->width, | |
| 1152 | − S5K6AA_WIN_WIDTH_MAX); | |
| 1153 | − crop->height = clamp_t(unsigned int, crop->height, mf->height, | |
| 1154 | − S5K6AA_WIN_HEIGHT_MAX); | |
| 1155 | − crop->left = clamp_t(unsigned int, crop->left, 0, | |
| 1156 | − S5K6AA_WIN_WIDTH_MAX - crop->width); | |
| 1157 | − crop->top = clamp_t(unsigned int, crop->top, 0, | |
| 1158 | − S5K6AA_WIN_HEIGHT_MAX - crop->height); | |
| 1159 | − | |
| 1160 | − /* Reset to minimum possible frame interval */ | |
| 1161 | − ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv); | |
| 1162 | − } | |
| 1163 | − mutex_unlock(&s5k6aa->lock); | |
| 1164 | − | |
| 1165 | − return ret; | |
| 1166 | −} | |
| 1167 | − | |
| 1168 | −static int s5k6aa_get_selection(struct v4l2_subdev *sd, | |
| 1169 | − struct v4l2_subdev_state *sd_state, | |
| 1170 | − struct v4l2_subdev_selection *sel) | |
| 1171 | −{ | |
| 1172 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 1173 | − struct v4l2_rect *rect; | |
| 1174 | − | |
| 1175 | − if (sel->target != V4L2_SEL_TGT_CROP) | |
| 1176 | − return -EINVAL; | |
| 1177 | − | |
| 1178 | − memset(sel->reserved, 0, sizeof(sel->reserved)); | |
| 1179 | − | |
| 1180 | − mutex_lock(&s5k6aa->lock); | |
| 1181 | − rect = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which); | |
| 1182 | − sel->r = *rect; | |
| 1183 | − mutex_unlock(&s5k6aa->lock); | |
| 1184 | − | |
| 1185 | − v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n", | |
| 1186 | − rect->left, rect->top, rect->width, rect->height); | |
| 1187 | − | |
| 1188 | − return 0; | |
| 1189 | −} | |
| 1190 | − | |
| 1191 | −static int s5k6aa_set_selection(struct v4l2_subdev *sd, | |
| 1192 | − struct v4l2_subdev_state *sd_state, | |
| 1193 | − struct v4l2_subdev_selection *sel) | |
| 1194 | −{ | |
| 1195 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 1196 | − struct v4l2_mbus_framefmt *mf; | |
| 1197 | − unsigned int max_x, max_y; | |
| 1198 | − struct v4l2_rect *crop_r; | |
| 1199 | − | |
| 1200 | − if (sel->target != V4L2_SEL_TGT_CROP) | |
| 1201 | − return -EINVAL; | |
| 1202 | − | |
| 1203 | − mutex_lock(&s5k6aa->lock); | |
| 1204 | − crop_r = __s5k6aa_get_crop_rect(s5k6aa, sd_state, sel->which); | |
| 1205 | − | |
| 1206 | − if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | |
| 1207 | − mf = &s5k6aa->preset->mbus_fmt; | |
| 1208 | − s5k6aa->apply_crop = 1; | |
| 1209 | − } else { | |
| 1210 | − mf = v4l2_subdev_get_try_format(sd, sd_state, 0); | |
| 1211 | − } | |
| 1212 | − v4l_bound_align_image(&sel->r.width, mf->width, | |
| 1213 | − S5K6AA_WIN_WIDTH_MAX, 1, | |
| 1214 | − &sel->r.height, mf->height, | |
| 1215 | − S5K6AA_WIN_HEIGHT_MAX, 1, 0); | |
| 1216 | − | |
| 1217 | − max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1; | |
| 1218 | − max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1; | |
| 1219 | − | |
| 1220 | − sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x); | |
| 1221 | − sel->r.top = clamp_t(unsigned int, sel->r.top, 0, max_y); | |
| 1222 | − | |
| 1223 | − *crop_r = sel->r; | |
| 1224 | − | |
| 1225 | − mutex_unlock(&s5k6aa->lock); | |
| 1226 | − | |
| 1227 | − v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n", | |
| 1228 | − crop_r->left, crop_r->top, crop_r->width, crop_r->height); | |
| 1229 | − | |
| 1230 | − return 0; | |
| 1231 | −} | |
| 1232 | − | |
| 1233 | −static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = { | |
| 1234 | − .enum_mbus_code = s5k6aa_enum_mbus_code, | |
| 1235 | − .enum_frame_size = s5k6aa_enum_frame_size, | |
| 1236 | − .enum_frame_interval = s5k6aa_enum_frame_interval, | |
| 1237 | − .get_fmt = s5k6aa_get_fmt, | |
| 1238 | − .set_fmt = s5k6aa_set_fmt, | |
| 1239 | − .get_selection = s5k6aa_get_selection, | |
| 1240 | − .set_selection = s5k6aa_set_selection, | |
| 1241 | −}; | |
| 1242 | − | |
| 1243 | −static const struct v4l2_subdev_video_ops s5k6aa_video_ops = { | |
| 1244 | − .g_frame_interval = s5k6aa_g_frame_interval, | |
| 1245 | − .s_frame_interval = s5k6aa_s_frame_interval, | |
| 1246 | − .s_stream = s5k6aa_s_stream, | |
| 1247 | −}; | |
| 1248 | − | |
| 1249 | −/* | |
| 1250 | − * V4L2 subdev controls | |
| 1251 | − */ | |
| 1252 | − | |
| 1253 | −static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 1254 | −{ | |
| 1255 | − struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | |
| 1256 | − struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 1257 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 1258 | − int idx, err = 0; | |
| 1259 | − | |
| 1260 | − v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val); | |
| 1261 | − | |
| 1262 | − mutex_lock(&s5k6aa->lock); | |
| 1263 | − /* | |
| 1264 | − * If the device is not powered up by the host driver do | |
| 1265 | − * not apply any controls to H/W at this time. Instead | |
| 1266 | − * the controls will be restored right after power-up. | |
| 1267 | − */ | |
| 1268 | − if (s5k6aa->power == 0) | |
| 1269 | − goto unlock; | |
| 1270 | − idx = s5k6aa->preset->index; | |
| 1271 | − | |
| 1272 | − switch (ctrl->id) { | |
| 1273 | − case V4L2_CID_AUTO_WHITE_BALANCE: | |
| 1274 | − err = s5k6aa_set_awb(s5k6aa, ctrl->val); | |
| 1275 | − break; | |
| 1276 | − | |
| 1277 | − case V4L2_CID_BRIGHTNESS: | |
| 1278 | − err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val); | |
| 1279 | − break; | |
| 1280 | − | |
| 1281 | − case V4L2_CID_COLORFX: | |
| 1282 | − err = s5k6aa_set_colorfx(s5k6aa, ctrl->val); | |
| 1283 | − break; | |
| 1284 | − | |
| 1285 | − case V4L2_CID_CONTRAST: | |
| 1286 | − err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val); | |
| 1287 | − break; | |
| 1288 | − | |
| 1289 | − case V4L2_CID_EXPOSURE_AUTO: | |
| 1290 | − err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val); | |
| 1291 | − break; | |
| 1292 | − | |
| 1293 | − case V4L2_CID_HFLIP: | |
| 1294 | − err = s5k6aa_set_mirror(s5k6aa, ctrl->val); | |
| 1295 | − if (err) | |
| 1296 | − break; | |
| 1297 | − err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | |
| 1298 | − break; | |
| 1299 | − | |
| 1300 | − case V4L2_CID_POWER_LINE_FREQUENCY: | |
| 1301 | − err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val); | |
| 1302 | − break; | |
| 1303 | − | |
| 1304 | − case V4L2_CID_SATURATION: | |
| 1305 | − err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val); | |
| 1306 | − break; | |
| 1307 | − | |
| 1308 | − case V4L2_CID_SHARPNESS: | |
| 1309 | − err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val); | |
| 1310 | − break; | |
| 1311 | − | |
| 1312 | − case V4L2_CID_WHITE_BALANCE_TEMPERATURE: | |
| 1313 | − err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val); | |
| 1314 | − if (err) | |
| 1315 | − break; | |
| 1316 | − err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | |
| 1317 | − break; | |
| 1318 | − } | |
| 1319 | −unlock: | |
| 1320 | − mutex_unlock(&s5k6aa->lock); | |
| 1321 | − return err; | |
| 1322 | −} | |
| 1323 | − | |
| 1324 | −static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = { | |
| 1325 | − .s_ctrl = s5k6aa_s_ctrl, | |
| 1326 | −}; | |
| 1327 | − | |
| 1328 | −static int s5k6aa_log_status(struct v4l2_subdev *sd) | |
| 1329 | −{ | |
| 1330 | − v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); | |
| 1331 | − return 0; | |
| 1332 | −} | |
| 1333 | − | |
| 1334 | −#define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001) | |
| 1335 | −#define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002) | |
| 1336 | −#define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003) | |
| 1337 | − | |
| 1338 | −static const struct v4l2_ctrl_config s5k6aa_ctrls[] = { | |
| 1339 | − { | |
| 1340 | − .ops = &s5k6aa_ctrl_ops, | |
| 1341 | − .id = V4L2_CID_RED_GAIN, | |
| 1342 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 1343 | − .name = "Gain, Red", | |
| 1344 | − .min = 0, | |
| 1345 | − .max = 256, | |
| 1346 | − .def = 127, | |
| 1347 | − .step = 1, | |
| 1348 | − }, { | |
| 1349 | − .ops = &s5k6aa_ctrl_ops, | |
| 1350 | − .id = V4L2_CID_GREEN_GAIN, | |
| 1351 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 1352 | − .name = "Gain, Green", | |
| 1353 | − .min = 0, | |
| 1354 | − .max = 256, | |
| 1355 | − .def = 127, | |
| 1356 | − .step = 1, | |
| 1357 | − }, { | |
| 1358 | − .ops = &s5k6aa_ctrl_ops, | |
| 1359 | − .id = V4L2_CID_BLUE_GAIN, | |
| 1360 | − .type = V4L2_CTRL_TYPE_INTEGER, | |
| 1361 | − .name = "Gain, Blue", | |
| 1362 | − .min = 0, | |
| 1363 | − .max = 256, | |
| 1364 | − .def = 127, | |
| 1365 | − .step = 1, | |
| 1366 | − }, | |
| 1367 | −}; | |
| 1368 | − | |
| 1369 | −static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa) | |
| 1370 | −{ | |
| 1371 | − const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops; | |
| 1372 | − struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; | |
| 1373 | − struct v4l2_ctrl_handler *hdl = &ctrls->handler; | |
| 1374 | − | |
| 1375 | − int ret = v4l2_ctrl_handler_init(hdl, 16); | |
| 1376 | − if (ret) | |
| 1377 | − return ret; | |
| 1378 | − /* Auto white balance cluster */ | |
| 1379 | − ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, | |
| 1380 | − 0, 1, 1, 1); | |
| 1381 | − ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL); | |
| 1382 | − ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL); | |
| 1383 | − ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL); | |
| 1384 | − v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false); | |
| 1385 | − | |
| 1386 | − ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 1387 | − ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 1388 | − v4l2_ctrl_cluster(2, &ctrls->hflip); | |
| 1389 | − | |
| 1390 | − ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, | |
| 1391 | − V4L2_CID_EXPOSURE_AUTO, | |
| 1392 | − V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); | |
| 1393 | − /* Exposure time: x 1 us */ | |
| 1394 | − ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, | |
| 1395 | − 0, 6000000U, 1, 100000U); | |
| 1396 | − /* Total gain: 256 <=> 1x */ | |
| 1397 | − ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, | |
| 1398 | − 0, 256, 1, 256); | |
| 1399 | − v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false); | |
| 1400 | − | |
| 1401 | − v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, | |
| 1402 | − V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, | |
| 1403 | − V4L2_CID_POWER_LINE_FREQUENCY_AUTO); | |
| 1404 | − | |
| 1405 | − v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, | |
| 1406 | − V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE); | |
| 1407 | − | |
| 1408 | − v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE, | |
| 1409 | − 0, 256, 1, 0); | |
| 1410 | − | |
| 1411 | − v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0); | |
| 1412 | − v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0); | |
| 1413 | − v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0); | |
| 1414 | − v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0); | |
| 1415 | − | |
| 1416 | − if (hdl->error) { | |
| 1417 | − ret = hdl->error; | |
| 1418 | − v4l2_ctrl_handler_free(hdl); | |
| 1419 | − return ret; | |
| 1420 | − } | |
| 1421 | − | |
| 1422 | − s5k6aa->sd.ctrl_handler = hdl; | |
| 1423 | − return 0; | |
| 1424 | −} | |
| 1425 | − | |
| 1426 | −/* | |
| 1427 | − * V4L2 subdev internal operations | |
| 1428 | − */ | |
| 1429 | −static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 1430 | −{ | |
| 1431 | − struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, | |
| 1432 | − fh->state, | |
| 1433 | − 0); | |
| 1434 | − struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0); | |
| 1435 | − | |
| 1436 | − format->colorspace = s5k6aa_formats[0].colorspace; | |
| 1437 | − format->code = s5k6aa_formats[0].code; | |
| 1438 | − format->width = S5K6AA_OUT_WIDTH_DEF; | |
| 1439 | − format->height = S5K6AA_OUT_HEIGHT_DEF; | |
| 1440 | − format->field = V4L2_FIELD_NONE; | |
| 1441 | − | |
| 1442 | − crop->width = S5K6AA_WIN_WIDTH_MAX; | |
| 1443 | − crop->height = S5K6AA_WIN_HEIGHT_MAX; | |
| 1444 | − crop->left = 0; | |
| 1445 | − crop->top = 0; | |
| 1446 | − | |
| 1447 | − return 0; | |
| 1448 | −} | |
| 1449 | − | |
| 1450 | −static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa) | |
| 1451 | −{ | |
| 1452 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 1453 | − u16 api_ver = 0, fw_rev = 0; | |
| 1454 | − | |
| 1455 | − int ret = s5k6aa_set_ahb_address(client); | |
| 1456 | − | |
| 1457 | − if (!ret) | |
| 1458 | − ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver); | |
| 1459 | − if (!ret) | |
| 1460 | − ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev); | |
| 1461 | − if (ret) { | |
| 1462 | − v4l2_err(&s5k6aa->sd, "FW revision check failed!\n"); | |
| 1463 | − return ret; | |
| 1464 | − } | |
| 1465 | − | |
| 1466 | − v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n", | |
| 1467 | − api_ver, fw_rev); | |
| 1468 | − | |
| 1469 | − return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV; | |
| 1470 | −} | |
| 1471 | − | |
| 1472 | −static int s5k6aa_registered(struct v4l2_subdev *sd) | |
| 1473 | −{ | |
| 1474 | − struct s5k6aa *s5k6aa = to_s5k6aa(sd); | |
| 1475 | − int ret; | |
| 1476 | − | |
| 1477 | − mutex_lock(&s5k6aa->lock); | |
| 1478 | − ret = __s5k6aa_power_on(s5k6aa); | |
| 1479 | − if (!ret) { | |
| 1480 | − msleep(100); | |
| 1481 | − ret = s5k6aa_check_fw_revision(s5k6aa); | |
| 1482 | − __s5k6aa_power_off(s5k6aa); | |
| 1483 | − } | |
| 1484 | − mutex_unlock(&s5k6aa->lock); | |
| 1485 | − | |
| 1486 | − return ret; | |
| 1487 | −} | |
| 1488 | − | |
| 1489 | −static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = { | |
| 1490 | − .registered = s5k6aa_registered, | |
| 1491 | − .open = s5k6aa_open, | |
| 1492 | −}; | |
| 1493 | − | |
| 1494 | −static const struct v4l2_subdev_core_ops s5k6aa_core_ops = { | |
| 1495 | − .s_power = s5k6aa_set_power, | |
| 1496 | − .log_status = s5k6aa_log_status, | |
| 1497 | −}; | |
| 1498 | − | |
| 1499 | −static const struct v4l2_subdev_ops s5k6aa_subdev_ops = { | |
| 1500 | − .core = &s5k6aa_core_ops, | |
| 1501 | − .pad = &s5k6aa_pad_ops, | |
| 1502 | − .video = &s5k6aa_video_ops, | |
| 1503 | −}; | |
| 1504 | − | |
| 1505 | −/* | |
| 1506 | − * GPIO setup | |
| 1507 | − */ | |
| 1508 | − | |
| 1509 | −static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa, | |
| 1510 | − const struct s5k6aa_platform_data *pdata) | |
| 1511 | −{ | |
| 1512 | − struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | |
| 1513 | − const struct s5k6aa_gpio *gpio; | |
| 1514 | − unsigned long flags; | |
| 1515 | − int ret; | |
| 1516 | − | |
| 1517 | − s5k6aa->gpio[STBY].gpio = -EINVAL; | |
| 1518 | − s5k6aa->gpio[RSET].gpio = -EINVAL; | |
| 1519 | − | |
| 1520 | − gpio = &pdata->gpio_stby; | |
| 1521 | − if (gpio_is_valid(gpio->gpio)) { | |
| 1522 | − flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW) | |
| 1523 | − | GPIOF_EXPORT; | |
| 1524 | − ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags, | |
| 1525 | − "S5K6AA_STBY"); | |
| 1526 | − if (ret < 0) | |
| 1527 | − return ret; | |
| 1528 | − | |
| 1529 | − s5k6aa->gpio[STBY] = *gpio; | |
| 1530 | − } | |
| 1531 | − | |
| 1532 | − gpio = &pdata->gpio_reset; | |
| 1533 | − if (gpio_is_valid(gpio->gpio)) { | |
| 1534 | − flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW) | |
| 1535 | − | GPIOF_EXPORT; | |
| 1536 | − ret = devm_gpio_request_one(&client->dev, gpio->gpio, flags, | |
| 1537 | − "S5K6AA_RST"); | |
| 1538 | − if (ret < 0) | |
| 1539 | − return ret; | |
| 1540 | − | |
| 1541 | − s5k6aa->gpio[RSET] = *gpio; | |
| 1542 | − } | |
| 1543 | − | |
| 1544 | − return 0; | |
| 1545 | −} | |
| 1546 | − | |
| 1547 | −static int s5k6aa_probe(struct i2c_client *client) | |
| 1548 | −{ | |
| 1549 | − const struct s5k6aa_platform_data *pdata = client->dev.platform_data; | |
| 1550 | − struct v4l2_subdev *sd; | |
| 1551 | − struct s5k6aa *s5k6aa; | |
| 1552 | − int i, ret; | |
| 1553 | − | |
| 1554 | − if (pdata == NULL) { | |
| 1555 | − dev_err(&client->dev, "Platform data not specified\n"); | |
| 1556 | − return -EINVAL; | |
| 1557 | − } | |
| 1558 | − | |
| 1559 | − if (pdata->mclk_frequency == 0) { | |
| 1560 | − dev_err(&client->dev, "MCLK frequency not specified\n"); | |
| 1561 | − return -EINVAL; | |
| 1562 | − } | |
| 1563 | − | |
| 1564 | − s5k6aa = devm_kzalloc(&client->dev, sizeof(*s5k6aa), GFP_KERNEL); | |
| 1565 | − if (!s5k6aa) | |
| 1566 | − return -ENOMEM; | |
| 1567 | − | |
| 1568 | − mutex_init(&s5k6aa->lock); | |
| 1569 | − | |
| 1570 | − s5k6aa->mclk_frequency = pdata->mclk_frequency; | |
| 1571 | − s5k6aa->bus_type = pdata->bus_type; | |
| 1572 | − s5k6aa->mipi_lanes = pdata->nlanes; | |
| 1573 | − s5k6aa->s_power = pdata->set_power; | |
| 1574 | − s5k6aa->inv_hflip = pdata->horiz_flip; | |
| 1575 | − s5k6aa->inv_vflip = pdata->vert_flip; | |
| 1576 | − | |
| 1577 | − sd = &s5k6aa->sd; | |
| 1578 | − v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); | |
| 1579 | − /* Static name; NEVER use in new drivers! */ | |
| 1580 | − strscpy(sd->name, DRIVER_NAME, sizeof(sd->name)); | |
| 1581 | − | |
| 1582 | − sd->internal_ops = &s5k6aa_subdev_internal_ops; | |
| 1583 | − sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1584 | − | |
| 1585 | − s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 1586 | − sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 1587 | − ret = media_entity_pads_init(&sd->entity, 1, &s5k6aa->pad); | |
| 1588 | − if (ret) | |
| 1589 | − return ret; | |
| 1590 | − | |
| 1591 | − ret = s5k6aa_configure_gpios(s5k6aa, pdata); | |
| 1592 | − if (ret) | |
| 1593 | − goto out_err; | |
| 1594 | − | |
| 1595 | − for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++) | |
| 1596 | − s5k6aa->supplies[i].supply = s5k6aa_supply_names[i]; | |
| 1597 | − | |
| 1598 | − ret = devm_regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES, | |
| 1599 | − s5k6aa->supplies); | |
| 1600 | − if (ret) { | |
| 1601 | − dev_err(&client->dev, "Failed to get regulators\n"); | |
| 1602 | − goto out_err; | |
| 1603 | − } | |
| 1604 | − | |
| 1605 | − ret = s5k6aa_initialize_ctrls(s5k6aa); | |
| 1606 | − if (ret) | |
| 1607 | − goto out_err; | |
| 1608 | − | |
| 1609 | − s5k6aa_presets_data_init(s5k6aa); | |
| 1610 | − | |
| 1611 | − s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX; | |
| 1612 | − s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX; | |
| 1613 | − s5k6aa->ccd_rect.left = 0; | |
| 1614 | − s5k6aa->ccd_rect.top = 0; | |
| 1615 | − | |
| 1616 | − return 0; | |
| 1617 | − | |
| 1618 | −out_err: | |
| 1619 | − media_entity_cleanup(&s5k6aa->sd.entity); | |
| 1620 | − return ret; | |
| 1621 | −} | |
| 1622 | − | |
| 1623 | −static void s5k6aa_remove(struct i2c_client *client) | |
| 1624 | −{ | |
| 1625 | − struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1626 | − | |
| 1627 | − v4l2_device_unregister_subdev(sd); | |
| 1628 | − v4l2_ctrl_handler_free(sd->ctrl_handler); | |
| 1629 | − media_entity_cleanup(&sd->entity); | |
| 1630 | −} | |
| 1631 | − | |
| 1632 | −static const struct i2c_device_id s5k6aa_id[] = { | |
| 1633 | − { DRIVER_NAME, 0 }, | |
| 1634 | − { }, | |
| 1635 | −}; | |
| 1636 | −MODULE_DEVICE_TABLE(i2c, s5k6aa_id); | |
| 1637 | − | |
| 1638 | − | |
| 1639 | −static struct i2c_driver s5k6aa_i2c_driver = { | |
| 1640 | − .driver = { | |
| 1641 | − .name = DRIVER_NAME | |
| 1642 | − }, | |
| 1643 | − .probe_new = s5k6aa_probe, | |
| 1644 | − .remove = s5k6aa_remove, | |
| 1645 | − .id_table = s5k6aa_id, | |
| 1646 | −}; | |
| 1647 | − | |
| 1648 | −module_i2c_driver(s5k6aa_i2c_driver); | |
| 1649 | − | |
| 1650 | −MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); | |
| 1651 | −MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | |
| 1652 | −MODULE_LICENSE("GPL"); | |
| @@ -1,762 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/* | |
| 3 | − * Driver for SiliconFile SR030PC30 VGA (1/10-Inch) Image Sensor with ISP | |
| 4 | − * | |
| 5 | − * Copyright (C) 2010 Samsung Electronics Co., Ltd | |
| 6 | − * Author: Sylwester Nawrocki, s.nawrocki@samsung.com | |
| 7 | − * | |
| 8 | − * Based on original driver authored by Dongsoo Nathaniel Kim | |
| 9 | − * and HeungJun Kim <riverful.kim@samsung.com>. | |
| 10 | − * | |
| 11 | − * Based on mt9v011 Micron Digital Image Sensor driver | |
| 12 | − * Copyright (c) 2009 Mauro Carvalho Chehab | |
| 13 | − */ | |
| 14 | − | |
| 15 | −#include <linux/i2c.h> | |
| 16 | −#include <linux/delay.h> | |
| 17 | −#include <linux/slab.h> | |
| 18 | −#include <linux/module.h> | |
| 19 | −#include <media/v4l2-device.h> | |
| 20 | −#include <media/v4l2-subdev.h> | |
| 21 | −#include <media/v4l2-mediabus.h> | |
| 22 | −#include <media/v4l2-ctrls.h> | |
| 23 | −#include <media/i2c/sr030pc30.h> | |
| 24 | − | |
| 25 | −static int debug; | |
| 26 | −module_param(debug, int, 0644); | |
| 27 | − | |
| 28 | −#define MODULE_NAME "SR030PC30" | |
| 29 | − | |
| 30 | −/* | |
| 31 | − * Register offsets within a page | |
| 32 | − * b15..b8 - page id, b7..b0 - register address | |
| 33 | − */ | |
| 34 | −#define POWER_CTRL_REG 0x0001 | |
| 35 | −#define PAGEMODE_REG 0x03 | |
| 36 | −#define DEVICE_ID_REG 0x0004 | |
| 37 | −#define NOON010PC30_ID 0x86 | |
| 38 | −#define SR030PC30_ID 0x8C | |
| 39 | −#define VDO_CTL1_REG 0x0010 | |
| 40 | −#define SUBSAMPL_NONE_VGA 0 | |
| 41 | −#define SUBSAMPL_QVGA 0x10 | |
| 42 | −#define SUBSAMPL_QQVGA 0x20 | |
| 43 | −#define VDO_CTL2_REG 0x0011 | |
| 44 | −#define SYNC_CTL_REG 0x0012 | |
| 45 | −#define WIN_ROWH_REG 0x0020 | |
| 46 | −#define WIN_ROWL_REG 0x0021 | |
| 47 | −#define WIN_COLH_REG 0x0022 | |
| 48 | −#define WIN_COLL_REG 0x0023 | |
| 49 | −#define WIN_HEIGHTH_REG 0x0024 | |
| 50 | −#define WIN_HEIGHTL_REG 0x0025 | |
| 51 | −#define WIN_WIDTHH_REG 0x0026 | |
| 52 | −#define WIN_WIDTHL_REG 0x0027 | |
| 53 | −#define HBLANKH_REG 0x0040 | |
| 54 | −#define HBLANKL_REG 0x0041 | |
| 55 | −#define VSYNCH_REG 0x0042 | |
| 56 | −#define VSYNCL_REG 0x0043 | |
| 57 | −/* page 10 */ | |
| 58 | −#define ISP_CTL_REG(n) (0x1010 + (n)) | |
| 59 | −#define YOFS_REG 0x1040 | |
| 60 | −#define DARK_YOFS_REG 0x1041 | |
| 61 | −#define AG_ABRTH_REG 0x1050 | |
| 62 | −#define SAT_CTL_REG 0x1060 | |
| 63 | −#define BSAT_REG 0x1061 | |
| 64 | −#define RSAT_REG 0x1062 | |
| 65 | −#define AG_SAT_TH_REG 0x1063 | |
| 66 | −/* page 11 */ | |
| 67 | −#define ZLPF_CTRL_REG 0x1110 | |
| 68 | −#define ZLPF_CTRL2_REG 0x1112 | |
| 69 | −#define ZLPF_AGH_THR_REG 0x1121 | |
| 70 | −#define ZLPF_THR_REG 0x1160 | |
| 71 | −#define ZLPF_DYN_THR_REG 0x1160 | |
| 72 | −/* page 12 */ | |
| 73 | −#define YCLPF_CTL1_REG 0x1240 | |
| 74 | −#define YCLPF_CTL2_REG 0x1241 | |
| 75 | −#define YCLPF_THR_REG 0x1250 | |
| 76 | −#define BLPF_CTL_REG 0x1270 | |
| 77 | −#define BLPF_THR1_REG 0x1274 | |
| 78 | −#define BLPF_THR2_REG 0x1275 | |
| 79 | −/* page 14 - Lens Shading Compensation */ | |
| 80 | −#define LENS_CTRL_REG 0x1410 | |
| 81 | −#define LENS_XCEN_REG 0x1420 | |
| 82 | −#define LENS_YCEN_REG 0x1421 | |
| 83 | −#define LENS_R_COMP_REG 0x1422 | |
| 84 | −#define LENS_G_COMP_REG 0x1423 | |
| 85 | −#define LENS_B_COMP_REG 0x1424 | |
| 86 | −/* page 15 - Color correction */ | |
| 87 | −#define CMC_CTL_REG 0x1510 | |
| 88 | −#define CMC_OFSGH_REG 0x1514 | |
| 89 | −#define CMC_OFSGL_REG 0x1516 | |
| 90 | −#define CMC_SIGN_REG 0x1517 | |
| 91 | −/* Color correction coefficients */ | |
| 92 | −#define CMC_COEF_REG(n) (0x1530 + (n)) | |
| 93 | −/* Color correction offset coefficients */ | |
| 94 | −#define CMC_OFS_REG(n) (0x1540 + (n)) | |
| 95 | −/* page 16 - Gamma correction */ | |
| 96 | −#define GMA_CTL_REG 0x1610 | |
| 97 | −/* Gamma correction coefficients 0.14 */ | |
| 98 | −#define GMA_COEF_REG(n) (0x1630 + (n)) | |
| 99 | −/* page 20 - Auto Exposure */ | |
| 100 | −#define AE_CTL1_REG 0x2010 | |
| 101 | −#define AE_CTL2_REG 0x2011 | |
| 102 | −#define AE_FRM_CTL_REG 0x2020 | |
| 103 | −#define AE_FINE_CTL_REG(n) (0x2028 + (n)) | |
| 104 | −#define EXP_TIMEH_REG 0x2083 | |
| 105 | −#define EXP_TIMEM_REG 0x2084 | |
| 106 | −#define EXP_TIMEL_REG 0x2085 | |
| 107 | −#define EXP_MMINH_REG 0x2086 | |
| 108 | −#define EXP_MMINL_REG 0x2087 | |
| 109 | −#define EXP_MMAXH_REG 0x2088 | |
| 110 | −#define EXP_MMAXM_REG 0x2089 | |
| 111 | −#define EXP_MMAXL_REG 0x208A | |
| 112 | −/* page 22 - Auto White Balance */ | |
| 113 | −#define AWB_CTL1_REG 0x2210 | |
| 114 | −#define AWB_ENABLE 0x80 | |
| 115 | −#define AWB_CTL2_REG 0x2211 | |
| 116 | −#define MWB_ENABLE 0x01 | |
| 117 | −/* RGB gain control (manual WB) when AWB_CTL1[7]=0 */ | |
| 118 | −#define AWB_RGAIN_REG 0x2280 | |
| 119 | −#define AWB_GGAIN_REG 0x2281 | |
| 120 | −#define AWB_BGAIN_REG 0x2282 | |
| 121 | −#define AWB_RMAX_REG 0x2283 | |
| 122 | −#define AWB_RMIN_REG 0x2284 | |
| 123 | −#define AWB_BMAX_REG 0x2285 | |
| 124 | −#define AWB_BMIN_REG 0x2286 | |
| 125 | −/* R, B gain range in bright light conditions */ | |
| 126 | −#define AWB_RMAXB_REG 0x2287 | |
| 127 | −#define AWB_RMINB_REG 0x2288 | |
| 128 | −#define AWB_BMAXB_REG 0x2289 | |
| 129 | −#define AWB_BMINB_REG 0x228A | |
| 130 | −/* manual white balance, when AWB_CTL2[0]=1 */ | |
| 131 | −#define MWB_RGAIN_REG 0x22B2 | |
| 132 | −#define MWB_BGAIN_REG 0x22B3 | |
| 133 | −/* the token to mark an array end */ | |
| 134 | −#define REG_TERM 0xFFFF | |
| 135 | − | |
| 136 | −/* Minimum and maximum exposure time in ms */ | |
| 137 | −#define EXPOS_MIN_MS 1 | |
| 138 | −#define EXPOS_MAX_MS 125 | |
| 139 | − | |
| 140 | −struct sr030pc30_info { | |
| 141 | − struct v4l2_subdev sd; | |
| 142 | − struct v4l2_ctrl_handler hdl; | |
| 143 | − const struct sr030pc30_platform_data *pdata; | |
| 144 | − const struct sr030pc30_format *curr_fmt; | |
| 145 | − const struct sr030pc30_frmsize *curr_win; | |
| 146 | − unsigned int hflip:1; | |
| 147 | − unsigned int vflip:1; | |
| 148 | − unsigned int sleep:1; | |
| 149 | − struct { | |
| 150 | − /* auto whitebalance control cluster */ | |
| 151 | − struct v4l2_ctrl *awb; | |
| 152 | − struct v4l2_ctrl *red; | |
| 153 | − struct v4l2_ctrl *blue; | |
| 154 | − }; | |
| 155 | − struct { | |
| 156 | − /* auto exposure control cluster */ | |
| 157 | − struct v4l2_ctrl *autoexp; | |
| 158 | − struct v4l2_ctrl *exp; | |
| 159 | − }; | |
| 160 | − u8 i2c_reg_page; | |
| 161 | −}; | |
| 162 | − | |
| 163 | −struct sr030pc30_format { | |
| 164 | − u32 code; | |
| 165 | − enum v4l2_colorspace colorspace; | |
| 166 | − u16 ispctl1_reg; | |
| 167 | −}; | |
| 168 | − | |
| 169 | −struct sr030pc30_frmsize { | |
| 170 | − u16 width; | |
| 171 | − u16 height; | |
| 172 | − int vid_ctl1; | |
| 173 | −}; | |
| 174 | − | |
| 175 | −struct i2c_regval { | |
| 176 | − u16 addr; | |
| 177 | − u16 val; | |
| 178 | −}; | |
| 179 | − | |
| 180 | −/* supported resolutions */ | |
| 181 | −static const struct sr030pc30_frmsize sr030pc30_sizes[] = { | |
| 182 | − { | |
| 183 | − .width = 640, | |
| 184 | − .height = 480, | |
| 185 | − .vid_ctl1 = SUBSAMPL_NONE_VGA, | |
| 186 | − }, { | |
| 187 | − .width = 320, | |
| 188 | − .height = 240, | |
| 189 | − .vid_ctl1 = SUBSAMPL_QVGA, | |
| 190 | − }, { | |
| 191 | − .width = 160, | |
| 192 | − .height = 120, | |
| 193 | − .vid_ctl1 = SUBSAMPL_QQVGA, | |
| 194 | − }, | |
| 195 | −}; | |
| 196 | − | |
| 197 | −/* supported pixel formats */ | |
| 198 | −static const struct sr030pc30_format sr030pc30_formats[] = { | |
| 199 | − { | |
| 200 | − .code = MEDIA_BUS_FMT_YUYV8_2X8, | |
| 201 | − .colorspace = V4L2_COLORSPACE_JPEG, | |
| 202 | − .ispctl1_reg = 0x03, | |
| 203 | − }, { | |
| 204 | − .code = MEDIA_BUS_FMT_YVYU8_2X8, | |
558 more lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 855 lines aren’t shown here.
This diff is large: its 326 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 595 lines aren’t shown here.
This diff is large: its 142 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 456 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 377 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 564 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 167 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 303 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 454 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 222 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 372 lines aren’t shown here.
This diff is large: its 1021 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 385 lines aren’t shown here.
This diff is large: its 282 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 274 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 617 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 540 lines aren’t shown here.
This diff is large: its 395 lines aren’t shown here.
This diff is large: its 530 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 651 lines aren’t shown here.
This diff is large: its 859 lines aren’t shown here.
This diff is large: its 868 lines aren’t shown here.
This diff is large: its 419 lines aren’t shown here.
This diff is large: its 1513 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 205 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 119 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 222 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 152 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 198 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 416 lines aren’t shown here.
This diff is large: its 1236 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 492 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 1573 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 710 lines aren’t shown here.
This diff is large: its 228 lines aren’t shown here.
This diff is large: its 341 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 343 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 306 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 324 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 368 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.