Pull media updates from Mauro Carvalho Chehab: - Legacy soc_camera driver was removed from staging - New I2C sensor related drivers: dw9768, ch7322, max9271, rdacm20 - TI vpe driver code was re-organized and had new features added - Added Xilinx MIPI CSI-2 Rx Subsystem driver - Added support for Infrared Toy and IR Droid devices - Lots of random driver fixes, new features and cleanups * tag 'media/v5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (318 commits) media: camss: fix memory leaks on error handling paths in probe media: davinci: vpif_capture: fix potential double free media: radio: remove redundant assignment to variable retval media: allegro: fix potential null dereference on header media: mtk-mdp: Fix a refcounting bug on error in init media: allegro: fix an error pointer vs NULL check media: meye: fix missing pm_mchip_mode field media: cafe-driver: use generic power management media: saa7164: use generic power management media: v4l2-dev/ioctl: Fix document for VIDIOC_QUERYCAP media: v4l2: Correct kernel-doc inconsistency media: v4l2: Correct kernel-doc inconsistency media: dvbdev.h: keep * together with the type media: v4l2-subdev.h: keep * together with the type media: videobuf2: Print videobuf2 buffer state by name media: colorspaces-details.rst: fix V4L2_COLORSPACE_JPEG description media: tw68: use generic power management media: meye: use generic power management media: cx88: use generic power management media: cx25821: use generic power management ...
Unified · Split
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | 2 | ||
| 3 | .. include:: <isonum.txt> | 3 | .. include:: <isonum.txt> |
| 4 | 4 | ||
| 5 | The Samsung S5P/EXYNOS4 FIMC driver | 5 | The Samsung S5P/Exynos4 FIMC driver |
| 6 | =================================== | 6 | =================================== |
| 7 | 7 | ||
| 8 | Copyright |copy| 2012 - 2013 Samsung Electronics Co., Ltd. | 8 | Copyright |copy| 2012 - 2013 Samsung Electronics Co., Ltd. |
| @@ -19,7 +19,7 @@ drivers/media/platform/exynos4-is directory. · 10 unmodified lines | |||
| 19 | Supported SoCs | 19 | Supported SoCs |
| 20 | -------------- | 20 | -------------- |
| 21 | 21 | ||
| 22 | S5PC100 (mem-to-mem only), S5PV210, EXYNOS4210 | 22 | S5PC100 (mem-to-mem only), S5PV210, Exynos4210 |
| 23 | 23 | ||
| 24 | Supported features | 24 | Supported features |
| 25 | ------------------ | 25 | ------------------ |
| @@ -45,7 +45,7 @@ Media device interface · 19 unmodified lines | |||
| 45 | ~~~~~~~~~~~~~~~~~~~~~~ | 45 | ~~~~~~~~~~~~~~~~~~~~~~ |
| 46 | 46 | ||
| 47 | The driver supports Media Controller API as defined at :ref:`media_controller`. | 47 | The driver supports Media Controller API as defined at :ref:`media_controller`. |
| 48 | The media device driver name is "SAMSUNG S5P FIMC". | 48 | The media device driver name is "Samsung S5P FIMC". |
| 49 | 49 | ||
| 50 | The purpose of this interface is to allow changing assignment of FIMC instances | 50 | The purpose of this interface is to allow changing assignment of FIMC instances |
| 51 | to the SoC peripheral camera input at runtime and optionally to control internal | 51 | to the SoC peripheral camera input at runtime and optionally to control internal |
| @@ -293,6 +293,15 @@ all configurable using the following module options: · 292 unmodified lines | |||
| 293 | - 0: vmalloc | 293 | - 0: vmalloc |
| 294 | - 1: dma-contig | 294 | - 1: dma-contig |
| 295 | 295 | ||
| 296 | - cache_hints: | ||
| 297 | |||
| 298 | specifies if the device should set queues' user-space cache and memory | ||
| 299 | consistency hint capability (V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS). | ||
| 300 | The hints are valid only when using MMAP streaming I/O. Default is 0. | ||
| 301 | |||
| 302 | - 0: forbid hints | ||
| 303 | - 1: allow hints | ||
| 304 | |||
| 296 | Taken together, all these module options allow you to precisely customize | 305 | Taken together, all these module options allow you to precisely customize |
| 297 | the driver behavior and test your application with all sorts of permutations. | 306 | the driver behavior and test your application with all sorts of permutations. |
| 298 | It is also very suitable to emulate hardware that is not yet available, e.g. | 307 | It is also very suitable to emulate hardware that is not yet available, e.g. |
| @@ -0,0 +1,67 @@ | |||
| 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/chrontel,ch7322.yaml#" | ||
| 5 | $schema: "http://devicetree.org/meta-schemas/core.yaml#" | ||
| 6 | |||
| 7 | title: Chrontel HDMI-CEC Controller | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Jeff Chase <jnchase@google.com> | ||
| 11 | |||
| 12 | description: | ||
| 13 | The Chrontel CH7322 is a discrete HDMI-CEC controller. It is | ||
| 14 | programmable through I2C and drives a single CEC line. | ||
| 15 | |||
| 16 | properties: | ||
| 17 | compatible: | ||
| 18 | const: chrontel,ch7322 | ||
| 19 | |||
| 20 | reg: | ||
| 21 | description: I2C device address | ||
| 22 | maxItems: 1 | ||
| 23 | |||
| 24 | clocks: | ||
| 25 | maxItems: 1 | ||
| 26 | |||
| 27 | interrupts: | ||
| 28 | maxItems: 1 | ||
| 29 | |||
| 30 | reset-gpios: | ||
| 31 | description: | ||
| 32 | Reference to the GPIO connected to the RESET pin, if any. This | ||
| 33 | pin is active-low. | ||
| 34 | maxItems: 1 | ||
| 35 | |||
| 36 | standby-gpios: | ||
| 37 | description: | ||
| 38 | Reference to the GPIO connected to the OE pin, if any. When low | ||
| 39 | the device will respond to power status requests with "standby" | ||
| 40 | if in auto mode. | ||
| 41 | maxItems: 1 | ||
| 42 | |||
| 43 | # see ../cec.txt | ||
| 44 | hdmi-phandle: | ||
| 45 | description: phandle to the HDMI controller | ||
| 46 | |||
| 47 | required: | ||
| 48 | - compatible | ||
| 49 | - reg | ||
| 50 | - interrupts | ||
| 51 | |||
| 52 | examples: | ||
| 53 | - | | ||
| 54 | #include <dt-bindings/gpio/gpio.h> | ||
| 55 | #include <dt-bindings/interrupt-controller/irq.h> | ||
| 56 | i2c { | ||
| 57 | #address-cells = <1>; | ||
| 58 | #size-cells = <0>; | ||
| 59 | ch7322@75 { | ||
| 60 | compatible = "chrontel,ch7322"; | ||
| 61 | reg = <0x75>; | ||
| 62 | interrupts = <47 IRQ_TYPE_EDGE_RISING>; | ||
| 63 | standby-gpios = <&gpio 16 GPIO_ACTIVE_LOW>; | ||
| 64 | reset-gpios = <&gpio 15 GPIO_ACTIVE_LOW>; | ||
| 65 | hdmi-phandle = <&hdmi>; | ||
| 66 | }; | ||
| 67 | }; | ||
| @@ -0,0 +1,100 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | # Copyright (c) 2020 MediaTek Inc. | ||
| 3 | %YAML 1.2 | ||
| 4 | --- | ||
| 5 | $id: http://devicetree.org/schemas/media/i2c/dongwoon,dw9768.yaml# | ||
| 6 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 7 | |||
| 8 | title: Dongwoon Anatech DW9768 Voice Coil Motor (VCM) Lens Device Tree Bindings | ||
| 9 | |||
| 10 | maintainers: | ||
| 11 | - Dongchun Zhu <dongchun.zhu@mediatek.com> | ||
| 12 | |||
| 13 | description: |- | ||
| 14 | The Dongwoon DW9768 is a single 10-bit digital-to-analog (DAC) converter | ||
| 15 | with 100 mA output current sink capability. VCM current is controlled with | ||
| 16 | a linear mode driver. The DAC is controlled via a 2-wire (I2C-compatible) | ||
| 17 | serial interface that operates at clock rates up to 1MHz. This chip | ||
| 18 | integrates Advanced Actuator Control (AAC) technology and is intended for | ||
| 19 | driving voice coil lenses in camera modules. | ||
| 20 | |||
| 21 | properties: | ||
| 22 | compatible: | ||
| 23 | enum: | ||
| 24 | - dongwoon,dw9768 # for DW9768 VCM | ||
| 25 | - giantec,gt9769 # for GT9769 VCM | ||
| 26 | |||
| 27 | reg: | ||
| 28 | maxItems: 1 | ||
| 29 | |||
| 30 | vin-supply: | ||
| 31 | description: | ||
| 32 | Definition of the regulator used as Digital I/O voltage supply. | ||
| 33 | |||
| 34 | vdd-supply: | ||
| 35 | description: | ||
| 36 | Definition of the regulator used as Digital core voltage supply. | ||
| 37 | |||
| 38 | dongwoon,aac-mode: | ||
| 39 | description: | ||
| 40 | Indication of AAC mode select. | ||
| 41 | allOf: | ||
| 42 | - $ref: "/schemas/types.yaml#/definitions/uint32" | ||
| 43 | - enum: | ||
| 44 | - 1 # AAC2 mode(operation time# 0.48 x Tvib) | ||
| 45 | - 2 # AAC3 mode(operation time# 0.70 x Tvib) | ||
| 46 | - 3 # AAC4 mode(operation time# 0.75 x Tvib) | ||
| 47 | - 5 # AAC8 mode(operation time# 1.13 x Tvib) | ||
| 48 | default: 2 | ||
| 49 | |||
| 50 | dongwoon,aac-timing: | ||
| 51 | description: | ||
| 52 | Number of AAC Timing count that controlled by one 6-bit period of | ||
| 53 | vibration register AACT[5:0], the unit of which is 100 us. | ||
| 54 | allOf: | ||
| 55 | - $ref: "/schemas/types.yaml#/definitions/uint32" | ||
| 56 | - default: 0x20 | ||
| 57 | minimum: 0x00 | ||
| 58 | maximum: 0x3f | ||
| 59 | |||
| 60 | dongwoon,clock-presc: | ||
| 61 | description: | ||
| 62 | Indication of VCM internal clock dividing rate select, as one multiple | ||
| 63 | factor to calculate VCM ring periodic time Tvib. | ||
| 64 | allOf: | ||
| 65 | - $ref: "/schemas/types.yaml#/definitions/uint32" | ||
| 66 | - enum: | ||
| 67 | - 0 # Dividing Rate - 2 | ||
| 68 | - 1 # Dividing Rate - 1 | ||
| 69 | - 2 # Dividing Rate - 1/2 | ||
| 70 | - 3 # Dividing Rate - 1/4 | ||
| 71 | - 4 # Dividing Rate - 8 | ||
| 72 | - 5 # Dividing Rate - 4 | ||
| 73 | default: 1 | ||
| 74 | |||
| 75 | required: | ||
| 76 | - compatible | ||
| 77 | - reg | ||
| 78 | - vin-supply | ||
| 79 | - vdd-supply | ||
| 80 | |||
| 81 | additionalProperties: false | ||
| 82 | |||
| 83 | examples: | ||
| 84 | - | | ||
| 85 | |||
| 86 | i2c { | ||
| 87 | #address-cells = <1>; | ||
| 88 | #size-cells = <0>; | ||
| 89 | |||
| 90 | dw9768: camera-lens@c { | ||
| 91 | compatible = "dongwoon,dw9768"; | ||
| 92 | reg = <0x0c>; | ||
| 93 | |||
| 94 | vin-supply = <&mt6358_vcamio_reg>; | ||
| 95 | vdd-supply = <&mt6358_vcama2_reg>; | ||
| 96 | dongwoon,aac-timing = <0x39>; | ||
| 97 | }; | ||
| 98 | }; | ||
| 99 | |||
| 100 | ... | ||
| @@ -0,0 +1,159 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause | ||
| 2 | # Copyright (C) 2019 Renesas Electronics Corp. | ||
| 3 | %YAML 1.2 | ||
| 4 | --- | ||
| 5 | $id: http://devicetree.org/schemas/media/i2c/imi,rdacm2x-gmsl.yaml# | ||
| 6 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 7 | |||
| 8 | title: IMI D&D RDACM20 and RDACM21 Automotive Camera Platforms | ||
| 9 | |||
| 10 | maintainers: | ||
| 11 | - Jacopo Mondi <jacopo+renesas@jmondi.org> | ||
| 12 | - Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> | ||
| 13 | - Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | ||
| 14 | - Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> | ||
| 15 | |||
| 16 | description: -| | ||
| 17 | The IMI D&D RDACM20 and RDACM21 are GMSL-compatible camera designed for | ||
| 18 | automotive applications. | ||
| 19 | |||
| 20 | The RDACM20 camera module encloses a Maxim Integrated MAX9271 GMSL serializer, | ||
| 21 | coupled with an OV10635 image sensor and an embedded MCU. Both the MCU and | ||
| 22 | the image sensor are connected to the serializer local I2C bus and are | ||
| 23 | accessible by the host SoC by direct addressing. | ||
| 24 | |||
| 25 | The RDACM21 camera module encloses the same serializer, coupled with an | ||
| 26 | OV10640 image sensor and an OV490 ISP. Only the OV490 ISP is interfaced to | ||
| 27 | the serializer local I2C bus while the image sensor is not accessible from | ||
| 28 | the host SoC. | ||
| 29 | |||
| 30 | They both connect to a remote GMSL endpoint through a coaxial cable. | ||
| 31 | |||
| 32 | IMI RDACM20 | ||
| 33 | +---------------+ +--------------------------------+ | ||
| 34 | | GMSL | <- Video Stream | <- Video--------\ | | ||
| 35 | | |< === GMSL Link ====== >|MAX9271<- I2C bus-> <-->OV10635 | | ||
| 36 | | de-serializer | <- I2C messages -> | \<-->MCU | | ||
| 37 | +---------------+ +--------------------------------+ | ||
| 38 | |||
| 39 | IMI RDACM21 | ||
| 40 | +---------------+ +--------------------------------+ | ||
| 41 | | GMSL | <- Video Stream | <- Video--------\ | | ||
| 42 | | |< === GMSL Link ====== >|MAX9271<- I2C bus-> <-->OV490 | | ||
| 43 | | | <- I2C messages -> | | | | ||
| 44 | | de-serializer | | OV10640 <-------| | | ||
| 45 | +---------------+ +--------------------------------+ | ||
| 46 | |||
| 47 | Both camera modules serialize video data generated by the embedded camera | ||
| 48 | sensor on the GMSL serial channel to a remote GMSL de-serializer. They also | ||
| 49 | receive and transmit I2C messages encapsulated and transmitted on the GMSL | ||
| 50 | bidirectional control channel. | ||
| 51 | |||
| 52 | All I2C traffic received on the GMSL link not directed to the serializer is | ||
| 53 | propagated on the local I2C bus to the remote device there connected. All the | ||
| 54 | I2C traffic generated on the local I2C bus not directed to the serializer is | ||
| 55 | propagated to the remote de-serializer encapsulated in the GMSL control | ||
| 56 | channel. | ||
| 57 | |||
| 58 | The RDACM20 and RDACM21 DT node should be a direct child of the GMSL | ||
| 59 | deserializer's I2C bus corresponding to the GMSL link that the camera is | ||
| 60 | attached to. | ||
| 61 | |||
| 62 | properties: | ||
| 63 | '#address-cells': | ||
| 64 | const: 1 | ||
| 65 | |||
| 66 | '#size-cells': | ||
| 67 | const: 0 | ||
| 68 | |||
| 69 | compatible: | ||
| 70 | enum: | ||
| 71 | - imi,rdacm20 | ||
| 72 | - imi,rdacm21 | ||
| 73 | |||
| 74 | reg: | ||
| 75 | description: -| | ||
| 76 | I2C device addresses, the first to be assigned to the serializer, the | ||
| 77 | following ones to be assigned to the remote devices. | ||
| 78 | |||
| 79 | For RDACM20 the second entry of the property is assigned to the | ||
| 80 | OV10635 image sensor and the optional third one to the embedded MCU. | ||
| 81 | |||
| 82 | For RDACM21 the second entry is assigned to the OV490 ISP and the optional | ||
| 83 | third one ignored. | ||
| 84 | |||
| 85 | minItems: 2 | ||
| 86 | maxItems: 3 | ||
| 87 | |||
| 88 | port: | ||
| 89 | type: object | ||
| 90 | additionalProperties: false | ||
| 91 | description: -| | ||
| 92 | Connection to the remote GMSL endpoint are modelled using the OF graph | ||
| 93 | bindings in accordance with the video interface bindings defined in | ||
| 94 | Documentation/devicetree/bindings/media/video-interfaces.txt. | ||
| 95 | |||
| 96 | The device node contains a single "port" child node with a single | ||
| 97 | "endpoint" sub-device. | ||
| 98 | |||
| 99 | properties: | ||
| 100 | endpoint: | ||
| 101 | type: object | ||
| 102 | additionalProperties: false | ||
| 103 | |||
| 104 | properties: | ||
| 105 | remote-endpoint: | ||
| 106 | description: -| | ||
| 107 | phandle to the remote GMSL endpoint sub-node in the remote node | ||
| 108 | port. | ||
| 109 | maxItems: 1 | ||
| 110 | |||
| 111 | required: | ||
| 112 | - remote-endpoint | ||
| 113 | |||
| 114 | required: | ||
| 115 | - endpoint | ||
| 116 | |||
| 117 | required: | ||
| 118 | - compatible | ||
| 119 | - reg | ||
| 120 | - port | ||
| 121 | |||
| 122 | examples: | ||
| 123 | - | | ||
| 124 | i2c@e66d8000 { | ||
| 125 | #address-cells = <1>; | ||
| 126 | #size-cells = <0>; | ||
| 127 | |||
| 128 | reg = <0 0xe66d8000>; | ||
| 129 | |||
| 130 | camera@31 { | ||
| 131 | compatible = "imi,rdacm20"; | ||
| 132 | reg = <0x31>, <0x41>, <0x51>; | ||
| 133 | |||
| 134 | port { | ||
| 135 | rdacm20_out0: endpoint { | ||
| 136 | remote-endpoint = <&max9286_in0>; | ||
| 137 | }; | ||
| 138 | }; | ||
| 139 | }; | ||
| 140 | }; | ||
| 141 | |||
| 142 | - | | ||
| 143 | i2c@e66d8000 { | ||
| 144 | #address-cells = <1>; | ||
| 145 | #size-cells = <0>; | ||
| 146 | |||
| 147 | reg = <0 0xe66d8000>; | ||
| 148 | |||
| 149 | camera@31 { | ||
| 150 | compatible = "imi,rdacm21"; | ||
| 151 | reg = <0x31>, <0x41>; | ||
| 152 | |||
| 153 | port { | ||
| 154 | rdacm21_out0: endpoint { | ||
| 155 | remote-endpoint = <&max9286_in0>; | ||
| 156 | }; | ||
| 157 | }; | ||
| 158 | }; | ||
| 159 | }; | ||
| @@ -0,0 +1,366 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | # Copyright (C) 2019 Renesas Electronics Corp. | ||
| 3 | %YAML 1.2 | ||
| 4 | --- | ||
| 5 | $id: http://devicetree.org/schemas/media/i2c/maxim,max9286.yaml# | ||
| 6 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 7 | |||
| 8 | title: Maxim Integrated Quad GMSL Deserializer | ||
| 9 | |||
| 10 | maintainers: | ||
| 11 | - Jacopo Mondi <jacopo+renesas@jmondi.org> | ||
| 12 | - Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> | ||
| 13 | - Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | ||
| 14 | - Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> | ||
| 15 | |||
| 16 | description: | | ||
| 17 | The MAX9286 deserializer receives video data on up to 4 Gigabit Multimedia | ||
| 18 | Serial Links (GMSL) and outputs them on a CSI-2 D-PHY port using up to 4 data | ||
| 19 | lanes. | ||
| 20 | |||
| 21 | In addition to video data, the GMSL links carry a bidirectional control | ||
| 22 | channel that encapsulates I2C messages. The MAX9286 forwards all I2C traffic | ||
| 23 | not addressed to itself to the other side of the links, where a GMSL | ||
| 24 | serializer will output it on a local I2C bus. In the other direction all I2C | ||
| 25 | traffic received over GMSL by the MAX9286 is output on the local I2C bus. | ||
| 26 | |||
| 27 | properties: | ||
| 28 | '#address-cells': | ||
| 29 | const: 1 | ||
| 30 | |||
| 31 | '#size-cells': | ||
| 32 | const: 0 | ||
| 33 | |||
| 34 | compatible: | ||
| 35 | const: maxim,max9286 | ||
| 36 | |||
| 37 | reg: | ||
| 38 | description: I2C device address | ||
| 39 | maxItems: 1 | ||
| 40 | |||
| 41 | poc-supply: | ||
| 42 | description: Regulator providing Power over Coax to the cameras | ||
| 43 | maxItems: 1 | ||
| 44 | |||
| 45 | enable-gpios: | ||
| 46 | description: GPIO connected to the \#PWDN pin with inverted polarity | ||
| 47 | maxItems: 1 | ||
| 48 | |||
| 49 | gpio-controller: true | ||
| 50 | |||
| 51 | '#gpio-cells': | ||
| 52 | const: 2 | ||
| 53 | |||
| 54 | ports: | ||
| 55 | type: object | ||
| 56 | description: | | ||
| 57 | The connections to the MAX9286 GMSL and its endpoint nodes are modelled | ||
| 58 | using the OF graph bindings in accordance with the video interface | ||
| 59 | bindings defined in | ||
| 60 | Documentation/devicetree/bindings/media/video-interfaces.txt. | ||
| 61 | |||
| 62 | The following table lists the port number corresponding to each device | ||
| 63 | port. | ||
| 64 | |||
| 65 | Port Description | ||
| 66 | ---------------------------------------- | ||
| 67 | Port 0 GMSL Input 0 | ||
| 68 | Port 1 GMSL Input 1 | ||
| 69 | Port 2 GMSL Input 2 | ||
| 70 | Port 3 GMSL Input 3 | ||
| 71 | Port 4 CSI-2 Output | ||
| 72 | |||
| 73 | properties: | ||
| 74 | '#address-cells': | ||
| 75 | const: 1 | ||
| 76 | |||
| 77 | '#size-cells': | ||
| 78 | const: 0 | ||
| 79 | |||
| 80 | port@[0-3]: | ||
| 81 | type: object | ||
| 82 | properties: | ||
| 83 | reg: | ||
| 84 | enum: [ 0, 1, 2, 3 ] | ||
| 85 | |||
| 86 | endpoint: | ||
| 87 | type: object | ||
| 88 | |||
| 89 | properties: | ||
| 90 | remote-endpoint: | ||
| 91 | description: | | ||
| 92 | phandle to the remote GMSL source endpoint subnode in the | ||
| 93 | remote node port. | ||
| 94 | |||
| 95 | required: | ||
| 96 | - remote-endpoint | ||
| 97 | |||
| 98 | required: | ||
| 99 | - reg | ||
| 100 | - endpoint | ||
| 101 | |||
| 102 | additionalProperties: false | ||
| 103 | |||
| 104 | port@4: | ||
| 105 | type: object | ||
| 106 | properties: | ||
| 107 | reg: | ||
| 108 | const: 4 | ||
| 109 | |||
| 110 | endpoint: | ||
| 111 | type: object | ||
| 112 | |||
| 113 | properties: | ||
| 114 | remote-endpoint: | ||
| 115 | description: phandle to the remote CSI-2 sink endpoint. | ||
| 116 | |||
| 117 | data-lanes: | ||
| 118 | description: array of physical CSI-2 data lane indexes. | ||
| 119 | |||
| 120 | required: | ||
| 121 | - remote-endpoint | ||
| 122 | - data-lanes | ||
| 123 | |||
| 124 | required: | ||
| 125 | - reg | ||
| 126 | - endpoint | ||
| 127 | |||
| 128 | additionalProperties: false | ||
| 129 | |||
| 130 | required: | ||
| 131 | - port@4 | ||
| 132 | |||
| 133 | i2c-mux: | ||
| 134 | type: object | ||
| 135 | description: | | ||
| 136 | Each GMSL link is modelled as a child bus of an i2c bus | ||
| 137 | multiplexer/switch, in accordance with bindings described in | ||
| 138 | Documentation/devicetree/bindings/i2c/i2c-mux.txt. | ||
| 139 | |||
| 140 | properties: | ||
| 141 | '#address-cells': | ||
| 142 | const: 1 | ||
| 143 | |||
| 144 | '#size-cells': | ||
| 145 | const: 0 | ||
| 146 | |||
| 147 | patternProperties: | ||
| 148 | "^i2c@[0-3]$": | ||
| 149 | type: object | ||
| 150 | description: | | ||
| 151 | Child node of the i2c bus multiplexer which represents a GMSL link. | ||
| 152 | Each serializer device on the GMSL link remote end is represented with | ||
| 153 | an i2c-mux child node. The MAX9286 chip supports up to 4 GMSL | ||
| 154 | channels. | ||
| 155 | |||
| 156 | properties: | ||
| 157 | '#address-cells': | ||
| 158 | const: 1 | ||
| 159 | |||
| 160 | '#size-cells': | ||
| 161 | const: 0 | ||
| 162 | |||
| 163 | reg: | ||
| 164 | description: The index of the GMSL channel. | ||
| 165 | maxItems: 1 | ||
| 166 | |||
| 167 | patternProperties: | ||
| 168 | "^camera@[a-f0-9]+$": | ||
| 169 | type: object | ||
| 170 | description: | | ||
| 171 | The remote camera device, composed by a GMSL serializer and a | ||
| 172 | connected video source. | ||
| 173 | |||
| 174 | properties: | ||
| 175 | compatible: | ||
| 176 | description: The remote device compatible string. | ||
| 177 | |||
| 178 | reg: | ||
| 179 | minItems: 2 | ||
| 180 | maxItems: 3 | ||
| 181 | description: | | ||
| 182 | The I2C addresses to be assigned to the remote devices through | ||
| 183 | address reprogramming. The number of entries depends on the | ||
| 184 | requirements of the currently connected remote device. | ||
| 185 | |||
| 186 | port: | ||
| 187 | type: object | ||
| 188 | |||
| 189 | properties: | ||
| 190 | endpoint: | ||
| 191 | type: object | ||
| 192 | |||
| 193 | properties: | ||
| 194 | remote-endpoint: | ||
| 195 | description: phandle to the MAX9286 sink endpoint. | ||
| 196 | |||
| 197 | required: | ||
| 198 | - remote-endpoint | ||
| 199 | |||
| 200 | additionalProperties: false | ||
| 201 | |||
| 202 | required: | ||
| 203 | - endpoint | ||
| 204 | |||
| 205 | additionalProperties: false | ||
| 206 | |||
| 207 | required: | ||
| 208 | - compatible | ||
| 209 | - reg | ||
| 210 | - port | ||
| 211 | |||
| 212 | additionalProperties: false | ||
| 213 | |||
| 214 | additionalProperties: false | ||
| 215 | |||
| 216 | additionalProperties: false | ||
| 217 | |||
| 218 | required: | ||
| 219 | - compatible | ||
| 220 | - reg | ||
| 221 | - ports | ||
| 222 | - i2c-mux | ||
| 223 | - gpio-controller | ||
| 224 | |||
| 225 | additionalProperties: false | ||
| 226 | |||
| 227 | examples: | ||
| 228 | - | | ||
| 229 | #include <dt-bindings/gpio/gpio.h> | ||
| 230 | |||
| 231 | i2c@e66d8000 { | ||
| 232 | #address-cells = <1>; | ||
| 233 | #size-cells = <0>; | ||
| 234 | |||
| 235 | reg = <0 0xe66d8000>; | ||
| 236 | |||
| 237 | gmsl-deserializer@2c { | ||
| 238 | compatible = "maxim,max9286"; | ||
| 239 | reg = <0x2c>; | ||
| 240 | poc-supply = <&camera_poc_12v>; | ||
| 241 | enable-gpios = <&gpio 13 GPIO_ACTIVE_HIGH>; | ||
| 242 | |||
| 243 | gpio-controller; | ||
| 244 | #gpio-cells = <2>; | ||
| 245 | |||
| 246 | ports { | ||
| 247 | #address-cells = <1>; | ||
| 248 | #size-cells = <0>; | ||
| 249 | |||
| 250 | port@0 { | ||
| 251 | reg = <0>; | ||
| 252 | |||
| 253 | max9286_in0: endpoint { | ||
| 254 | remote-endpoint = <&rdacm20_out0>; | ||
| 255 | }; | ||
| 256 | }; | ||
| 257 | |||
| 258 | port@1 { | ||
| 259 | reg = <1>; | ||
| 260 | |||
| 261 | max9286_in1: endpoint { | ||
| 262 | remote-endpoint = <&rdacm20_out1>; | ||
| 263 | }; | ||
| 264 | }; | ||
| 265 | |||
| 266 | port@2 { | ||
| 267 | reg = <2>; | ||
| 268 | |||
| 269 | max9286_in2: endpoint { | ||
| 270 | remote-endpoint = <&rdacm20_out2>; | ||
| 271 | }; | ||
| 272 | }; | ||
| 273 | |||
| 274 | port@3 { | ||
| 275 | reg = <3>; | ||
| 276 | |||
| 277 | max9286_in3: endpoint { | ||
| 278 | remote-endpoint = <&rdacm20_out3>; | ||
| 279 | }; | ||
| 280 | }; | ||
| 281 | |||
| 282 | port@4 { | ||
| 283 | reg = <4>; | ||
| 284 | |||
| 285 | max9286_out: endpoint { | ||
| 286 | data-lanes = <1 2 3 4>; | ||
| 287 | remote-endpoint = <&csi40_in>; | ||
| 288 | }; | ||
| 289 | }; | ||
| 290 | }; | ||
| 291 | |||
| 292 | i2c-mux { | ||
| 293 | #address-cells = <1>; | ||
| 294 | #size-cells = <0>; | ||
| 295 | |||
| 296 | i2c@0 { | ||
| 297 | #address-cells = <1>; | ||
| 298 | #size-cells = <0>; | ||
| 299 | reg = <0>; | ||
| 300 | |||
| 301 | camera@51 { | ||
| 302 | compatible = "imi,rdacm20"; | ||
| 303 | reg = <0x51>, <0x61>; | ||
| 304 | |||
| 305 | port { | ||
| 306 | rdacm20_out0: endpoint { | ||
| 307 | remote-endpoint = <&max9286_in0>; | ||
| 308 | }; | ||
| 309 | }; | ||
| 310 | |||
| 311 | }; | ||
| 312 | }; | ||
| 313 | |||
| 314 | i2c@1 { | ||
| 315 | #address-cells = <1>; | ||
| 316 | #size-cells = <0>; | ||
| 317 | reg = <1>; | ||
| 318 | |||
| 319 | camera@52 { | ||
| 320 | compatible = "imi,rdacm20"; | ||
| 321 | reg = <0x52>, <0x62>; | ||
| 322 | |||
| 323 | port { | ||
| 324 | rdacm20_out1: endpoint { | ||
| 325 | remote-endpoint = <&max9286_in1>; | ||
| 326 | }; | ||
| 327 | }; | ||
| 328 | }; | ||
| 329 | }; | ||
| 330 | |||
| 331 | i2c@2 { | ||
| 332 | #address-cells = <1>; | ||
| 333 | #size-cells = <0>; | ||
| 334 | reg = <2>; | ||
| 335 | |||
| 336 | camera@53 { | ||
| 337 | compatible = "imi,rdacm20"; | ||
| 338 | reg = <0x53>, <0x63>; | ||
| 339 | |||
| 340 | port { | ||
| 341 | rdacm20_out2: endpoint { | ||
| 342 | remote-endpoint = <&max9286_in2>; | ||
| 343 | }; | ||
| 344 | }; | ||
| 345 | }; | ||
| 346 | }; | ||
| 347 | |||
| 348 | i2c@3 { | ||
| 349 | #address-cells = <1>; | ||
| 350 | #size-cells = <0>; | ||
| 351 | reg = <3>; | ||
| 352 | |||
| 353 | camera@54 { | ||
| 354 | compatible = "imi,rdacm20"; | ||
| 355 | reg = <0x54>, <0x64>; | ||
| 356 | |||
| 357 | port { | ||
| 358 | rdacm20_out3: endpoint { | ||
| 359 | remote-endpoint = <&max9286_in3>; | ||
| 360 | }; | ||
| 361 | }; | ||
| 362 | }; | ||
| 363 | }; | ||
| 364 | }; | ||
| 365 | }; | ||
| 366 | }; | ||
| @@ -1,34 +0,0 @@ | |||
| 1 | Renesas R-Car Frame Compression Processor (FCP) | ||
| 2 | ----------------------------------------------- | ||
| 3 | |||
| 4 | The FCP is a companion module of video processing modules in the Renesas R-Car | ||
| 5 | Gen3 and RZ/G2 SoCs. It provides data compression and decompression, data | ||
| 6 | caching, and conversion of AXI transactions in order to reduce the memory | ||
| 7 | bandwidth. | ||
| 8 | |||
| 9 | There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP | ||
| 10 | for FDP (FCPF). Their configuration and behaviour depend on the module they | ||
| 11 | are paired with. These DT bindings currently support the FCPV and FCPF. | ||
| 12 | |||
| 13 | - compatible: Must be one or more of the following | ||
| 14 | |||
| 15 | - "renesas,fcpv" for generic compatible 'FCP for VSP' | ||
| 16 | - "renesas,fcpf" for generic compatible 'FCP for FDP' | ||
| 17 | |||
| 18 | - reg: the register base and size for the device registers | ||
| 19 | - clocks: Reference to the functional clock | ||
| 20 | |||
| 21 | Optional properties: | ||
| 22 | - power-domains : power-domain property defined with a power domain specifier | ||
| 23 | to respective power domain. | ||
| 24 | |||
| 25 | |||
| 26 | Device node example | ||
| 27 | ------------------- | ||
| 28 | |||
| 29 | fcpvd1: fcp@fea2f000 { | ||
| 30 | compatible = "renesas,fcpv"; | ||
| 31 | reg = <0 0xfea2f000 0 0x200>; | ||
| 32 | clocks = <&cpg CPG_MOD 602>; | ||
| 33 | power-domains = <&sysc R8A7795_PD_A3VP>; | ||
| 34 | }; | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/media/renesas,fcp.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Renesas R-Car Frame Compression Processor (FCP) | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | The FCP is a companion module of video processing modules in the Renesas | ||
| 14 | R-Car Gen3 and RZ/G2 SoCs. It provides data compression and decompression, | ||
| 15 | data caching, and conversion of AXI transactions in order to reduce the | ||
| 16 | memory bandwidth. | ||
| 17 | |||
| 18 | There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and | ||
| 19 | FCP for FDP (FCPF). Their configuration and behaviour depend on the module | ||
| 20 | they are paired with. These DT bindings currently support the FCPV and FCPF. | ||
| 21 | |||
| 22 | properties: | ||
| 23 | compatible: | ||
| 24 | enum: | ||
| 25 | - renesas,fcpv # FCP for VSP | ||
| 26 | - renesas,fcpf # FCP for FDP | ||
| 27 | |||
| 28 | reg: | ||
| 29 | maxItems: 1 | ||
| 30 | |||
| 31 | clocks: | ||
| 32 | maxItems: 1 | ||
| 33 | |||
| 34 | iommus: | ||
| 35 | maxItems: 1 | ||
| 36 | |||
| 37 | power-domains: | ||
| 38 | maxItems: 1 | ||
| 39 | |||
| 40 | resets: | ||
| 41 | maxItems: 1 | ||
| 42 | |||
| 43 | required: | ||
| 44 | - compatible | ||
| 45 | - reg | ||
| 46 | - clocks | ||
| 47 | - power-domains | ||
| 48 | - resets | ||
| 49 | |||
| 50 | additionalProperties: false | ||
| 51 | |||
| 52 | examples: | ||
| 53 | # R8A7795 (R-Car H3) FCP for VSP-D1 | ||
| 54 | - | | ||
| 55 | #include <dt-bindings/clock/renesas-cpg-mssr.h> | ||
| 56 | #include <dt-bindings/power/r8a7795-sysc.h> | ||
| 57 | |||
| 58 | fcp@fea2f000 { | ||
| 59 | compatible = "renesas,fcpv"; | ||
| 60 | reg = <0xfea2f000 0x200>; | ||
| 61 | clocks = <&cpg CPG_MOD 602>; | ||
| 62 | power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; | ||
| 63 | resets = <&cpg 602>; | ||
| 64 | iommus = <&ipmmu_vi0 9>; | ||
| 65 | }; | ||
| 66 | ... | ||
| @@ -1,37 +0,0 @@ | |||
| 1 | Renesas R-Car Fine Display Processor (FDP1) | ||
| 2 | ------------------------------------------- | ||
| 3 | |||
| 4 | The FDP1 is a de-interlacing module which converts interlaced video to | ||
| 5 | progressive video. It is capable of performing pixel format conversion between | ||
| 6 | YCbCr/YUV formats and RGB formats. Only YCbCr/YUV formats are supported as | ||
| 7 | an input to the module. | ||
| 8 | |||
| 9 | Required properties: | ||
| 10 | |||
| 11 | - compatible: must be "renesas,fdp1" | ||
| 12 | - reg: the register base and size for the device registers | ||
| 13 | - interrupts : interrupt specifier for the FDP1 instance | ||
| 14 | - clocks: reference to the functional clock | ||
| 15 | |||
| 16 | Optional properties: | ||
| 17 | |||
| 18 | - power-domains: reference to the power domain that the FDP1 belongs to, if | ||
| 19 | any. | ||
| 20 | - renesas,fcp: a phandle referencing the FCP that handles memory accesses | ||
| 21 | for the FDP1. Not needed on Gen2, mandatory on Gen3. | ||
| 22 | |||
| 23 | Please refer to the binding documentation for the clock and/or power domain | ||
| 24 | providers for more details. | ||
| 25 | |||
| 26 | |||
| 27 | Device node example | ||
| 28 | ------------------- | ||
| 29 | |||
| 30 | fdp1@fe940000 { | ||
| 31 | compatible = "renesas,fdp1"; | ||
| 32 | reg = <0 0xfe940000 0 0x2400>; | ||
| 33 | interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>; | ||
| 34 | clocks = <&cpg CPG_MOD 119>; | ||
| 35 | power-domains = <&sysc R8A7795_PD_A3VP>; | ||
| 36 | renesas,fcp = <&fcpf0>; | ||
| 37 | }; | ||
| @@ -0,0 +1,69 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/media/renesas,fdp1.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Renesas R-Car Fine Display Processor (FDP1) | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 11 | |||
| 12 | description: | ||
| 13 | The FDP1 is a de-interlacing module which converts interlaced video to | ||
| 14 | progressive video. It is capable of performing pixel format conversion | ||
| 15 | between YCbCr/YUV formats and RGB formats. Only YCbCr/YUV formats are | ||
| 16 | supported as an input to the module. | ||
| 17 | |||
| 18 | properties: | ||
| 19 | compatible: | ||
| 20 | enum: | ||
| 21 | - renesas,fdp1 | ||
| 22 | |||
| 23 | reg: | ||
| 24 | maxItems: 1 | ||
| 25 | |||
| 26 | interrupts: | ||
| 27 | maxItems: 1 | ||
| 28 | |||
| 29 | clocks: | ||
| 30 | maxItems: 1 | ||
| 31 | |||
| 32 | power-domains: | ||
| 33 | maxItems: 1 | ||
| 34 | |||
| 35 | resets: | ||
| 36 | maxItems: 1 | ||
| 37 | |||
| 38 | renesas,fcp: | ||
| 39 | $ref: /schemas/types.yaml#/definitions/phandle | ||
| 40 | description: | ||
| 41 | A phandle referencing the FCP that handles memory accesses for the FDP1. | ||
| 42 | Not allowed on R-Car Gen2, mandatory on R-Car Gen3. | ||
| 43 | |||
| 44 | required: | ||
| 45 | - compatible | ||
| 46 | - reg | ||
| 47 | - interrupts | ||
| 48 | - clocks | ||
| 49 | - power-domains | ||
| 50 | - resets | ||
| 51 | |||
| 52 | additionalProperties: false | ||
| 53 | |||
| 54 | examples: | ||
| 55 | - | | ||
| 56 | #include <dt-bindings/clock/renesas-cpg-mssr.h> | ||
| 57 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 58 | #include <dt-bindings/power/r8a7795-sysc.h> | ||
| 59 | |||
| 60 | fdp1@fe940000 { | ||
| 61 | compatible = "renesas,fdp1"; | ||
| 62 | reg = <0xfe940000 0x2400>; | ||
| 63 | interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>; | ||
| 64 | clocks = <&cpg CPG_MOD 119>; | ||
| 65 | power-domains = <&sysc R8A7795_PD_A3VP>; | ||
| 66 | resets = <&cpg 119>; | ||
| 67 | renesas,fcp = <&fcpf0>; | ||
| 68 | }; | ||
| 69 | ... | ||
| @@ -1,30 +0,0 @@ | |||
| 1 | * Renesas VSP Video Processing Engine | ||
| 2 | |||
| 3 | The VSP is a video processing engine that supports up-/down-scaling, alpha | ||
| 4 | blending, color space conversion and various other image processing features. | ||
| 5 | It can be found in the Renesas R-Car Gen2, R-Car Gen3, RZ/G1, and RZ/G2 SoCs. | ||
| 6 | |||
| 7 | Required properties: | ||
| 8 | |||
| 9 | - compatible: Must contain one of the following values | ||
| 10 | - "renesas,vsp1" for the R-Car Gen2 and RZ/G1 VSP1 | ||
| 11 | - "renesas,vsp2" for the R-Car Gen3 and RZ/G2 VSP2 | ||
| 12 | |||
| 13 | - reg: Base address and length of the registers block for the VSP. | ||
| 14 | - interrupts: VSP interrupt specifier. | ||
| 15 | - clocks: A phandle + clock-specifier pair for the VSP functional clock. | ||
| 16 | |||
| 17 | Optional properties: | ||
| 18 | |||
| 19 | - renesas,fcp: A phandle referencing the FCP that handles memory accesses | ||
| 20 | for the VSP. Not needed on Gen2, mandatory on Gen3. | ||
| 21 | |||
| 22 | |||
| 23 | Example: R8A7790 (R-Car H2) VSP1-S node | ||
| 24 | |||
| 25 | vsp@fe928000 { | ||
| 26 | compatible = "renesas,vsp1"; | ||
| 27 | reg = <0 0xfe928000 0 0x8000>; | ||
| 28 | interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; | ||
| 29 | clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>; | ||
| 30 | }; | ||
| @@ -0,0 +1,97 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/media/renesas,vsp1.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Renesas VSP Video Processing Engine | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 11 | |||
| 12 | description: | ||
| 13 | The VSP is a video processing engine that supports up-/down-scaling, alpha | ||
| 14 | blending, color space conversion and various other image processing features. | ||
| 15 | It can be found in the Renesas R-Car Gen2, R-Car Gen3, RZ/G1, and RZ/G2 SoCs. | ||
| 16 | |||
| 17 | properties: | ||
| 18 | compatible: | ||
| 19 | enum: | ||
| 20 | - renesas,vsp1 # R-Car Gen2 and RZ/G1 | ||
| 21 | - renesas,vsp2 # R-Car Gen3 and RZ/G2 | ||
| 22 | |||
| 23 | reg: | ||
| 24 | maxItems: 1 | ||
| 25 | |||
| 26 | interrupts: | ||
| 27 | maxItems: 1 | ||
| 28 | |||
| 29 | clocks: | ||
| 30 | maxItems: 1 | ||
| 31 | |||
| 32 | power-domains: | ||
| 33 | maxItems: 1 | ||
| 34 | |||
| 35 | resets: | ||
| 36 | maxItems: 1 | ||
| 37 | |||
| 38 | renesas,fcp: | ||
| 39 | $ref: /schemas/types.yaml#/definitions/phandle | ||
| 40 | description: | ||
| 41 | A phandle referencing the FCP that handles memory accesses for the VSP. | ||
| 42 | |||
| 43 | required: | ||
| 44 | - compatible | ||
| 45 | - reg | ||
| 46 | - interrupts | ||
| 47 | - clocks | ||
| 48 | - power-domains | ||
| 49 | - resets | ||
| 50 | |||
| 51 | additionalProperties: false | ||
| 52 | |||
| 53 | if: | ||
| 54 | properties: | ||
| 55 | compatible: | ||
| 56 | items: | ||
| 57 | - const: renesas,vsp1 | ||
| 58 | then: | ||
| 59 | properties: | ||
| 60 | renesas,fcp: false | ||
| 61 | else: | ||
| 62 | required: | ||
| 63 | - renesas,fcp | ||
| 64 | |||
| 65 | examples: | ||
| 66 | # R8A7790 (R-Car H2) VSP1-S | ||
| 67 | - | | ||
| 68 | #include <dt-bindings/clock/renesas-cpg-mssr.h> | ||
| 69 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 70 | #include <dt-bindings/power/r8a7790-sysc.h> | ||
| 71 | |||
| 72 | vsp@fe928000 { | ||
| 73 | compatible = "renesas,vsp1"; | ||
| 74 | reg = <0xfe928000 0x8000>; | ||
| 75 | interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>; | ||
| 76 | clocks = <&cpg CPG_MOD 131>; | ||
| 77 | power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; | ||
| 78 | resets = <&cpg 131>; | ||
| 79 | }; | ||
| 80 | |||
| 81 | # R8A77951 (R-Car H3) VSP2-BC | ||
| 82 | - | | ||
| 83 | #include <dt-bindings/clock/renesas-cpg-mssr.h> | ||
| 84 | #include <dt-bindings/interrupt-controller/arm-gic.h> | ||
| 85 | #include <dt-bindings/power/r8a7795-sysc.h> | ||
| 86 | |||
| 87 | vsp@fe920000 { | ||
| 88 | compatible = "renesas,vsp2"; | ||
| 89 | reg = <0xfe920000 0x8000>; | ||
| 90 | interrupts = <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>; | ||
| 91 | clocks = <&cpg CPG_MOD 624>; | ||
| 92 | power-domains = <&sysc R8A7795_PD_A3VP>; | ||
| 93 | resets = <&cpg 624>; | ||
| 94 | |||
| 95 | renesas,fcp = <&fcpvb1>; | ||
| 96 | }; | ||
| 97 | ... | ||
| @@ -0,0 +1,237 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/media/xilinx/xlnx,csi2rxss.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Xilinx MIPI CSI-2 Receiver Subsystem | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Vishal Sagar <vishal.sagar@xilinx.com> | ||
| 11 | |||
| 12 | description: | | ||
| 13 | The Xilinx MIPI CSI-2 Receiver Subsystem is used to capture MIPI CSI-2 | ||
| 14 | traffic from compliant camera sensors and send the output as AXI4 Stream | ||
| 15 | video data for image processing. | ||
| 16 | The subsystem consists of a MIPI D-PHY in slave mode which captures the | ||
| 17 | data packets. This is passed along the MIPI CSI-2 Rx IP which extracts the | ||
| 18 | packet data. The optional Video Format Bridge (VFB) converts this data to | ||
| 19 | AXI4 Stream video data. | ||
| 20 | For more details, please refer to PG232 Xilinx MIPI CSI-2 Receiver Subsystem. | ||
| 21 | Please note that this bindings includes only the MIPI CSI-2 Rx controller | ||
| 22 | and Video Format Bridge and not D-PHY. | ||
| 23 | |||
| 24 | properties: | ||
| 25 | compatible: | ||
| 26 | items: | ||
| 27 | - enum: | ||
| 28 | - xlnx,mipi-csi2-rx-subsystem-5.0 | ||
| 29 | |||
| 30 | reg: | ||
| 31 | maxItems: 1 | ||
| 32 | |||
| 33 | interrupts: | ||
| 34 | maxItems: 1 | ||
| 35 | |||
| 36 | clocks: | ||
| 37 | description: List of clock specifiers | ||
| 38 | items: | ||
| 39 | - description: AXI Lite clock | ||
| 40 | - description: Video clock | ||
| 41 | |||
| 42 | clock-names: | ||
| 43 | items: | ||
| 44 | - const: lite_aclk | ||
| 45 | - const: video_aclk | ||
| 46 | |||
| 47 | xlnx,csi-pxl-format: | ||
| 48 | description: | | ||
| 49 | This denotes the CSI Data type selected in hw design. | ||
| 50 | Packets other than this data type (except for RAW8 and | ||
| 51 | User defined data types) will be filtered out. | ||
| 52 | Possible values are as below - | ||
| 53 | 0x1e - YUV4228B | ||
| 54 | 0x1f - YUV42210B | ||
| 55 | 0x20 - RGB444 | ||
| 56 | 0x21 - RGB555 | ||
| 57 | 0x22 - RGB565 | ||
| 58 | 0x23 - RGB666 | ||
| 59 | 0x24 - RGB888 | ||
| 60 | 0x28 - RAW6 | ||
| 61 | 0x29 - RAW7 | ||
| 62 | 0x2a - RAW8 | ||
| 63 | 0x2b - RAW10 | ||
| 64 | 0x2c - RAW12 | ||
| 65 | 0x2d - RAW14 | ||
| 66 | 0x2e - RAW16 | ||
| 67 | 0x2f - RAW20 | ||
| 68 | allOf: | ||
| 69 | - $ref: /schemas/types.yaml#/definitions/uint32 | ||
| 70 | - anyOf: | ||
| 71 | - minimum: 0x1e | ||
| 72 | - maximum: 0x24 | ||
| 73 | - minimum: 0x28 | ||
| 74 | - maximum: 0x2f | ||
| 75 | |||
| 76 | xlnx,vfb: | ||
| 77 | type: boolean | ||
| 78 | description: Present when Video Format Bridge is enabled in IP configuration | ||
| 79 | |||
| 80 | xlnx,en-csi-v2-0: | ||
| 81 | type: boolean | ||
| 82 | description: Present if CSI v2 is enabled in IP configuration. | ||
| 83 | |||
| 84 | xlnx,en-vcx: | ||
| 85 | type: boolean | ||
| 86 | description: | | ||
| 87 | When present, there are maximum 16 virtual channels, else only 4. | ||
| 88 | |||
| 89 | xlnx,en-active-lanes: | ||
| 90 | type: boolean | ||
| 91 | description: | | ||
| 92 | Present if the number of active lanes can be re-configured at | ||
| 93 | runtime in the Protocol Configuration Register. Otherwise all lanes, | ||
| 94 | as set in IP configuration, are always active. | ||
| 95 | |||
| 96 | video-reset-gpios: | ||
| 97 | description: Optional specifier for a GPIO that asserts video_aresetn. | ||
| 98 | maxItems: 1 | ||
| 99 | |||
| 100 | ports: | ||
| 101 | type: object | ||
| 102 | |||
| 103 | properties: | ||
| 104 | port@0: | ||
| 105 | type: object | ||
| 106 | description: | | ||
| 107 | Input / sink port node, single endpoint describing the | ||
| 108 | CSI-2 transmitter. | ||
| 109 | |||
| 110 | properties: | ||
| 111 | reg: | ||
| 112 | const: 0 | ||
| 113 | |||
| 114 | endpoint: | ||
| 115 | type: object | ||
| 116 | |||
| 117 | properties: | ||
| 118 | |||
| 119 | data-lanes: | ||
| 120 | description: | | ||
| 121 | This is required only in the sink port 0 endpoint which | ||
| 122 | connects to MIPI CSI-2 source like sensor. | ||
| 123 | The possible values are - | ||
| 124 | 1 - For 1 lane enabled in IP. | ||
| 125 | 1 2 - For 2 lanes enabled in IP. | ||
| 126 | 1 2 3 - For 3 lanes enabled in IP. | ||
| 127 | 1 2 3 4 - For 4 lanes enabled in IP. | ||
| 128 | items: | ||
| 129 | - const: 1 | ||
| 130 | - const: 2 | ||
| 131 | - const: 3 | ||
| 132 | - const: 4 | ||
| 133 | |||
| 134 | remote-endpoint: true | ||
| 135 | |||
| 136 | required: | ||
| 137 | - data-lanes | ||
| 138 | - remote-endpoint | ||
| 139 | |||
| 140 | additionalProperties: false | ||
| 141 | |||
| 142 | additionalProperties: false | ||
| 143 | |||
| 144 | port@1: | ||
| 145 | type: object | ||
| 146 | description: | | ||
| 147 | Output / source port node, endpoint describing modules | ||
| 148 | connected the CSI-2 receiver. | ||
| 149 | |||
| 150 | properties: | ||
| 151 | |||
| 152 | reg: | ||
| 153 | const: 1 | ||
| 154 | |||
| 155 | endpoint: | ||
| 156 | type: object | ||
| 157 | |||
| 158 | properties: | ||
| 159 | |||
| 160 | remote-endpoint: true | ||
| 161 | |||
| 162 | required: | ||
| 163 | - remote-endpoint | ||
| 164 | |||
| 165 | additionalProperties: false | ||
| 166 | |||
| 167 | additionalProperties: false | ||
| 168 | |||
| 169 | required: | ||
| 170 | - compatible | ||
| 171 | - reg | ||
| 172 | - interrupts | ||
| 173 | - clocks | ||
| 174 | - clock-names | ||
| 175 | - ports | ||
| 176 | |||
| 177 | allOf: | ||
| 178 | - if: | ||
| 179 | required: | ||
| 180 | - xlnx,vfb | ||
| 181 | then: | ||
| 182 | required: | ||
| 183 | - xlnx,csi-pxl-format | ||
| 184 | else: | ||
| 185 | properties: | ||
| 186 | xlnx,csi-pxl-format: false | ||
| 187 | |||
| 188 | - if: | ||
| 189 | not: | ||
| 190 | required: | ||
| 191 | - xlnx,en-csi-v2-0 | ||
| 192 | then: | ||
| 193 | properties: | ||
| 194 | xlnx,en-vcx: false | ||
| 195 | |||
| 196 | additionalProperties: false | ||
| 197 | |||
| 198 | examples: | ||
| 199 | - | | ||
| 200 | #include <dt-bindings/gpio/gpio.h> | ||
| 201 | xcsi2rxss_1: csi2rx@a0020000 { | ||
| 202 | compatible = "xlnx,mipi-csi2-rx-subsystem-5.0"; | ||
| 203 | reg = <0xa0020000 0x10000>; | ||
| 204 | interrupt-parent = <&gic>; | ||
| 205 | interrupts = <0 95 4>; | ||
| 206 | xlnx,csi-pxl-format = <0x2a>; | ||
| 207 | xlnx,vfb; | ||
| 208 | xlnx,en-active-lanes; | ||
| 209 | xlnx,en-csi-v2-0; | ||
| 210 | xlnx,en-vcx; | ||
| 211 | clock-names = "lite_aclk", "video_aclk"; | ||
| 212 | clocks = <&misc_clk_0>, <&misc_clk_1>; | ||
| 213 | video-reset-gpios = <&gpio 86 GPIO_ACTIVE_LOW>; | ||
| 214 | |||
| 215 | ports { | ||
| 216 | #address-cells = <1>; | ||
| 217 | #size-cells = <0>; | ||
| 218 | |||
| 219 | port@0 { | ||
| 220 | /* Sink port */ | ||
| 221 | reg = <0>; | ||
| 222 | csiss_in: endpoint { | ||
| 223 | data-lanes = <1 2 3 4>; | ||
| 224 | /* MIPI CSI-2 Camera handle */ | ||
| 225 | remote-endpoint = <&camera_out>; | ||
| 226 | }; | ||
| 227 | }; | ||
| 228 | port@1 { | ||
| 229 | /* Source port */ | ||
| 230 | reg = <1>; | ||
| 231 | csiss_out: endpoint { | ||
| 232 | remote-endpoint = <&vproc_in>; | ||
| 233 | }; | ||
| 234 | }; | ||
| 235 | }; | ||
| 236 | }; | ||
| 237 | ... | ||
| @@ -473,6 +473,8 @@ patternProperties: · 472 unmodified lines | |||
| 473 | description: ILI Technology Corporation (ILITEK) | 473 | description: ILI Technology Corporation (ILITEK) |
| 474 | "^img,.*": | 474 | "^img,.*": |
| 475 | description: Imagination Technologies Ltd. | 475 | description: Imagination Technologies Ltd. |
| 476 | "^imi,.*": | ||
| 477 | description: Integrated Micro-Electronics Inc. | ||
| 476 | "^incircuit,.*": | 478 | "^incircuit,.*": |
| 477 | description: In-Circuit GmbH | 479 | description: In-Circuit GmbH |
| 478 | "^inet-tek,.*": | 480 | "^inet-tek,.*": |
| @@ -20,7 +20,7 @@ last known snapshot and evolved the driver to the state it is in · 19 unmodified lines | |||
| 20 | here. | 20 | here. |
| 21 | 21 | ||
| 22 | More information on this driver can be found at: | 22 | More information on this driver can be found at: |
| 23 | http://www.isely.net/pvrusb2.html | 23 | https://www.isely.net/pvrusb2.html |
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | This driver has a strong separation of layers. They are very | 26 | This driver has a strong separation of layers. They are very |
| @@ -18,7 +18,7 @@ These differ mainly by the bandswitch byte. · 17 unmodified lines | |||
| 18 | Tuner Manufacturers | 18 | Tuner Manufacturers |
| 19 | ------------------- | 19 | ------------------- |
| 20 | 20 | ||
| 21 | - SAMSUNG Tuner identification: (e.g. TCPM9091PD27) | 21 | - Samsung Tuner identification: (e.g. TCPM9091PD27) |
| 22 | 22 | ||
| 23 | .. code-block:: none | 23 | .. code-block:: none |
| 24 | 24 | ||
| @@ -57,6 +57,9 @@ returns the information to the application. The ioctl never fails. · 56 unmodified lines | |||
| 57 | - ``name[32]`` | 57 | - ``name[32]`` |
| 58 | - The name of this CEC adapter. The combination ``driver`` and | 58 | - The name of this CEC adapter. The combination ``driver`` and |
| 59 | ``name`` must be unique. | 59 | ``name`` must be unique. |
| 60 | * - __u32 | ||
| 61 | - ``available_log_addrs`` | ||
| 62 | - The maximum number of logical addresses that can be configured. | ||
| 60 | * - __u32 | 63 | * - __u32 |
| 61 | - ``capabilities`` | 64 | - ``capabilities`` |
| 62 | - The capabilities of the CEC adapter, see | 65 | - The capabilities of the CEC adapter, see |
| @@ -34,8 +34,7 @@ Arguments · 33 unmodified lines | |||
| 34 | File descriptor returned by :ref:`open() <frontend_f_open>`. | 34 | File descriptor returned by :ref:`open() <frontend_f_open>`. |
| 35 | 35 | ||
| 36 | ``argp`` | 36 | ``argp`` |
| 37 | pointer to struct struct | 37 | pointer to struct :c:type:`dvb_frontend_info` |
| 38 | :c:type:`dvb_frontend_info` | ||
| 39 | 38 | ||
| 40 | 39 | ||
| 41 | Description | 40 | Description |
| @@ -23,8 +23,8 @@ argument to the :ref:`VIDIOC_QUERYBUF`, · 22 unmodified lines | |||
| 23 | :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and | 23 | :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and |
| 24 | :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. In the multi-planar API, | 24 | :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. In the multi-planar API, |
| 25 | some plane-specific members of struct :c:type:`v4l2_buffer`, | 25 | some plane-specific members of struct :c:type:`v4l2_buffer`, |
| 26 | such as pointers and sizes for each plane, are stored in struct | 26 | such as pointers and sizes for each plane, are stored in |
| 27 | struct :c:type:`v4l2_plane` instead. In that case, struct | 27 | struct :c:type:`v4l2_plane` instead. In that case, |
| 28 | struct :c:type:`v4l2_buffer` contains an array of plane structures. | 28 | struct :c:type:`v4l2_buffer` contains an array of plane structures. |
| 29 | 29 | ||
| 30 | Dequeued video buffers come with timestamps. The driver decides at which | 30 | Dequeued video buffers come with timestamps. The driver decides at which |
| @@ -577,7 +577,10 @@ Buffer Flags · 546 unmodified lines | |||
| 577 | applications shall use this flag if the data captured in the | 577 | applications shall use this flag if the data captured in the |
| 578 | buffer is not going to be touched by the CPU, instead the buffer | 578 | buffer is not going to be touched by the CPU, instead the buffer |
| 579 | will, probably, be passed on to a DMA-capable hardware unit for | 579 | will, probably, be passed on to a DMA-capable hardware unit for |
| 580 | further processing or output. | 580 | further processing or output. This flag is ignored unless the |
| 581 | queue is used for :ref:`memory mapping <mmap>` streaming I/O and | ||
| 582 | reports :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS | ||
| 583 | <V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS>` capability. | ||
| 581 | * .. _`V4L2-BUF-FLAG-NO-CACHE-CLEAN`: | 584 | * .. _`V4L2-BUF-FLAG-NO-CACHE-CLEAN`: |
| 582 | 585 | ||
| 583 | - ``V4L2_BUF_FLAG_NO_CACHE_CLEAN`` | 586 | - ``V4L2_BUF_FLAG_NO_CACHE_CLEAN`` |
| @@ -585,7 +588,10 @@ Buffer Flags · 1 unmodified line | |||
| 585 | - Caches do not have to be cleaned for this buffer. Typically | 588 | - Caches do not have to be cleaned for this buffer. Typically |
| 586 | applications shall use this flag for output buffers if the data in | 589 | applications shall use this flag for output buffers if the data in |
| 587 | this buffer has not been created by the CPU but by some | 590 | this buffer has not been created by the CPU but by some |
| 588 | DMA-capable unit, in which case caches have not been used. | 591 | DMA-capable unit, in which case caches have not been used. This flag |
| 592 | is ignored unless the queue is used for :ref:`memory mapping <mmap>` | ||
| 593 | streaming I/O and reports :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS | ||
| 594 | <V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS>` capability. | ||
| 589 | * .. _`V4L2-BUF-FLAG-M2M-HOLD-CAPTURE-BUF`: | 595 | * .. _`V4L2-BUF-FLAG-M2M-HOLD-CAPTURE-BUF`: |
| 590 | 596 | ||
| 591 | - ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` | 597 | - ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` |
| @@ -681,6 +687,36 @@ Buffer Flags · 89 unmodified lines | |||
| 681 | 687 | ||
| 682 | \normalsize | 688 | \normalsize |
| 683 | 689 | ||
| 690 | .. _memory-flags: | ||
| 691 | |||
| 692 | Memory Consistency Flags | ||
| 693 | ======================== | ||
| 694 | |||
| 695 | .. tabularcolumns:: |p{7.0cm}|p{2.2cm}|p{8.3cm}| | ||
| 696 | |||
| 697 | .. cssclass:: longtable | ||
| 698 | |||
| 699 | .. flat-table:: | ||
| 700 | :header-rows: 0 | ||
| 701 | :stub-columns: 0 | ||
| 702 | :widths: 3 1 4 | ||
| 703 | |||
| 704 | * .. _`V4L2-FLAG-MEMORY-NON-CONSISTENT`: | ||
| 705 | |||
| 706 | - ``V4L2_FLAG_MEMORY_NON_CONSISTENT`` | ||
| 707 | - 0x00000001 | ||
| 708 | - A buffer is allocated either in consistent (it will be automatically | ||
| 709 | coherent between the CPU and the bus) or non-consistent memory. The | ||
| 710 | latter can provide performance gains, for instance the CPU cache | ||
| 711 | sync/flush operations can be avoided if the buffer is accessed by the | ||
| 712 | corresponding device only and the CPU does not read/write to/from that | ||
| 713 | buffer. However, this requires extra care from the driver -- it must | ||
| 714 | guarantee memory consistency by issuing a cache flush/sync when | ||
| 715 | consistency is needed. If this flag is set V4L2 will attempt to | ||
| 716 | allocate the buffer in non-consistent memory. The flag takes effect | ||
| 717 | only if the buffer is used for :ref:`memory mapping <mmap>` I/O and the | ||
| 718 | queue reports the :ref:`V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS | ||
| 719 | <V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS>` capability. | ||
| 684 | 720 | ||
| 685 | .. c:type:: v4l2_memory | 721 | .. c:type:: v4l2_memory |
| 686 | 722 | ||
| @@ -767,8 +767,8 @@ scaled to [-128…128] and then clipped to [-128…127]. · 766 unmodified lines | |||
| 767 | information. So if something other than sRGB is used, then the driver | 767 | information. So if something other than sRGB is used, then the driver |
| 768 | will have to set that information explicitly. Effectively | 768 | will have to set that information explicitly. Effectively |
| 769 | ``V4L2_COLORSPACE_JPEG`` can be considered to be an abbreviation for | 769 | ``V4L2_COLORSPACE_JPEG`` can be considered to be an abbreviation for |
| 770 | ``V4L2_COLORSPACE_SRGB``, ``V4L2_YCBCR_ENC_601`` and | 770 | ``V4L2_COLORSPACE_SRGB``, ``V4L2_XFER_FUNC_SRGB``, ``V4L2_YCBCR_ENC_601`` |
| 771 | ``V4L2_QUANTIZATION_FULL_RANGE``. | 771 | and ``V4L2_QUANTIZATION_FULL_RANGE``. |
| 772 | 772 | ||
| 773 | *************************************** | 773 | *************************************** |
| 774 | Detailed Transfer Function Descriptions | 774 | Detailed Transfer Function Descriptions |
| @@ -247,7 +247,7 @@ Querying Capabilities · 246 unmodified lines | |||
| 247 | Initialization | 247 | Initialization |
| 248 | ============== | 248 | ============== |
| 249 | 249 | ||
| 250 | 1. Set the coded format on ``OUTPUT`` via :c:func:`VIDIOC_S_FMT` | 250 | 1. Set the coded format on ``OUTPUT`` via :c:func:`VIDIOC_S_FMT`. |
| 251 | 251 | ||
| 252 | * **Required fields:** | 252 | * **Required fields:** |
| 253 | 253 | ||
| @@ -803,7 +803,7 @@ it may be affected as per normal decoder operation. · 549 unmodified lines | |||
| 803 | * The decoder will drop all the pending ``OUTPUT`` buffers and they must be | 803 | * The decoder will drop all the pending ``OUTPUT`` buffers and they must be |
| 804 | treated as returned to the client (following standard semantics). | 804 | treated as returned to the client (following standard semantics). |
| 805 | 805 | ||
| 806 | 2. Restart the ``OUTPUT`` queue via :c:func:`VIDIOC_STREAMON` | 806 | 2. Restart the ``OUTPUT`` queue via :c:func:`VIDIOC_STREAMON`. |
| 807 | 807 | ||
| 808 | * **Required fields:** | 808 | * **Required fields:** |
| 809 | 809 | ||
| @@ -906,7 +906,9 @@ reflected by corresponding queries): · 96 unmodified lines | |||
| 906 | 906 | ||
| 907 | * visible resolution (selection rectangles), | 907 | * visible resolution (selection rectangles), |
| 908 | 908 | ||
| 909 | * the minimum number of buffers needed for decoding. | 909 | * the minimum number of buffers needed for decoding, |
| 910 | |||
| 911 | * bit-depth of the bitstream has been changed. | ||
| 910 | 912 | ||
| 911 | Whenever that happens, the decoder must proceed as follows: | 913 | Whenever that happens, the decoder must proceed as follows: |
| 912 | 914 | ||
| @@ -1059,7 +1061,7 @@ sequence was started. · 146 unmodified lines | |||
| 1059 | ``V4L2_DEC_CMD_STOP`` again while the drain sequence is in progress and they | 1061 | ``V4L2_DEC_CMD_STOP`` again while the drain sequence is in progress and they |
| 1060 | will fail with -EBUSY error code if attempted. | 1062 | will fail with -EBUSY error code if attempted. |
| 1061 | 1063 | ||
| 1062 | Although mandatory, the availability of decoder commands may be queried | 1064 | Although not mandatory, the availability of decoder commands may be queried |
| 1063 | using :c:func:`VIDIOC_TRY_DECODER_CMD`. | 1065 | using :c:func:`VIDIOC_TRY_DECODER_CMD`. |
| 1064 | 1066 | ||
| 1065 | End of Stream | 1067 | End of Stream |
| @@ -0,0 +1,753 @@ | |||
| 1 | .. This file is dual-licensed: you can use it either under the terms | ||
| 2 | .. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this | ||
| 3 | .. dual licensing only applies to this file, and not this project as a | ||
| 4 | .. whole. | ||
| 5 | .. | ||
| 6 | .. a) This file is free software; you can redistribute it and/or | ||
| 7 | .. modify it under the terms of the GNU General Public License as | ||
| 8 | .. published by the Free Software Foundation version 2 of | ||
| 9 | .. the License. | ||
| 10 | .. | ||
| 11 | .. This file is distributed in the hope that it will be useful, | ||
| 12 | .. but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | .. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | .. GNU General Public License for more details. | ||
| 15 | .. | ||
| 16 | .. Or, alternatively, | ||
| 17 | .. | ||
| 18 | .. b) Permission is granted to copy, distribute and/or modify this | ||
| 19 | .. document under the terms of the GNU Free Documentation License, | ||
| 20 | .. Version 1.1 or any later version published by the Free Software | ||
| 21 | .. Foundation, with no Invariant Sections, no Front-Cover Texts | ||
| 22 | .. and no Back-Cover Texts. A copy of the license is included at | ||
| 23 | .. Documentation/userspace-api/media/fdl-appendix.rst. | ||
| 24 | .. | ||
| 25 | .. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections | ||
| 26 | |||
| 27 | .. _encoder: | ||
| 28 | |||
| 29 | ************************************************* | ||
| 30 | Memory-to-Memory Stateful Video Encoder Interface | ||
| 31 | ************************************************* | ||
| 32 | |||
| 33 | A stateful video encoder takes raw video frames in display order and encodes | ||
| 34 | them into a bytestream. It generates complete chunks of the bytestream, including | ||
| 35 | all metadata, headers, etc. The resulting bytestream does not require any | ||
| 36 | further post-processing by the client. | ||
| 37 | |||
| 38 | Performing software stream processing, header generation etc. in the driver | ||
| 39 | in order to support this interface is strongly discouraged. In case such | ||
| 40 | operations are needed, use of the Stateless Video Encoder Interface (in | ||
| 41 | development) is strongly advised. | ||
| 42 | |||
| 43 | Conventions and Notations Used in This Document | ||
| 44 | =============================================== | ||
| 45 | |||
| 46 | 1. The general V4L2 API rules apply if not specified in this document | ||
| 47 | otherwise. | ||
| 48 | |||
| 49 | 2. The meaning of words "must", "may", "should", etc. is as per `RFC | ||
| 50 | 2119 <https://tools.ietf.org/html/rfc2119>`_. | ||
| 51 | |||
| 52 | 3. All steps not marked "optional" are required. | ||
| 53 | |||
| 54 | 4. :c:func:`VIDIOC_G_EXT_CTRLS` and :c:func:`VIDIOC_S_EXT_CTRLS` may be used | ||
| 55 | interchangeably with :c:func:`VIDIOC_G_CTRL` and :c:func:`VIDIOC_S_CTRL`, | ||
| 56 | unless specified otherwise. | ||
| 57 | |||
| 58 | 5. Single-planar API (see :ref:`planar-apis`) and applicable structures may be | ||
| 59 | used interchangeably with multi-planar API, unless specified otherwise, | ||
| 60 | depending on encoder capabilities and following the general V4L2 guidelines. | ||
| 61 | |||
| 62 | 6. i = [a..b]: sequence of integers from a to b, inclusive, i.e. i = | ||
| 63 | [0..2]: i = 0, 1, 2. | ||
| 64 | |||
| 65 | 7. Given an ``OUTPUT`` buffer A, then A' represents a buffer on the ``CAPTURE`` | ||
| 66 | queue containing data that resulted from processing buffer A. | ||
| 67 | |||
| 68 | Glossary | ||
| 69 | ======== | ||
| 70 | |||
| 71 | Refer to :ref:`decoder-glossary`. | ||
| 72 | |||
| 73 | State Machine | ||
| 74 | ============= | ||
| 75 | |||
| 76 | .. kernel-render:: DOT | ||
| 77 | :alt: DOT digraph of encoder state machine | ||
| 78 | :caption: Encoder State Machine | ||
| 79 | |||
| 80 | digraph encoder_state_machine { | ||
| 81 | node [shape = doublecircle, label="Encoding"] Encoding; | ||
| 82 | |||
| 83 | node [shape = circle, label="Initialization"] Initialization; | ||
| 84 | node [shape = circle, label="Stopped"] Stopped; | ||
| 85 | node [shape = circle, label="Drain"] Drain; | ||
| 86 | node [shape = circle, label="Reset"] Reset; | ||
| 87 | |||
| 88 | node [shape = point]; qi | ||
| 89 | qi -> Initialization [ label = "open()" ]; | ||
| 90 | |||
| 91 | Initialization -> Encoding [ label = "Both queues streaming" ]; | ||
| 92 | |||
| 93 | Encoding -> Drain [ label = "V4L2_ENC_CMD_STOP" ]; | ||
| 94 | Encoding -> Reset [ label = "VIDIOC_STREAMOFF(CAPTURE)" ]; | ||
| 95 | Encoding -> Stopped [ label = "VIDIOC_STREAMOFF(OUTPUT)" ]; | ||
| 96 | Encoding -> Encoding; | ||
| 97 | |||
| 98 | Drain -> Stopped [ label = "All CAPTURE\nbuffers dequeued\nor\nVIDIOC_STREAMOFF(OUTPUT)" ]; | ||
| 99 | Drain -> Reset [ label = "VIDIOC_STREAMOFF(CAPTURE)" ]; | ||
| 100 | |||
| 101 | Reset -> Encoding [ label = "VIDIOC_STREAMON(CAPTURE)" ]; | ||
| 102 | Reset -> Initialization [ label = "VIDIOC_REQBUFS(OUTPUT, 0)" ]; | ||
| 103 | |||
| 104 | Stopped -> Encoding [ label = "V4L2_ENC_CMD_START\nor\nVIDIOC_STREAMON(OUTPUT)" ]; | ||
| 105 | Stopped -> Reset [ label = "VIDIOC_STREAMOFF(CAPTURE)" ]; | ||
| 106 | } | ||
| 107 | |||
| 108 | Querying Capabilities | ||
| 109 | ===================== | ||
| 110 | |||
| 111 | 1. To enumerate the set of coded formats supported by the encoder, the | ||
| 112 | client may call :c:func:`VIDIOC_ENUM_FMT` on ``CAPTURE``. | ||
| 113 | |||
| 114 | * The full set of supported formats will be returned, regardless of the | ||
| 115 | format set on ``OUTPUT``. | ||
| 116 | |||
| 117 | 2. To enumerate the set of supported raw formats, the client may call | ||
| 118 | :c:func:`VIDIOC_ENUM_FMT` on ``OUTPUT``. | ||
| 119 | |||
| 120 | * Only the formats supported for the format currently active on ``CAPTURE`` | ||
| 121 | will be returned. | ||
| 122 | |||
| 123 | * In order to enumerate raw formats supported by a given coded format, | ||
| 124 | the client must first set that coded format on ``CAPTURE`` and then | ||
| 125 | enumerate the formats on ``OUTPUT``. | ||
| 126 | |||
| 127 | 3. The client may use :c:func:`VIDIOC_ENUM_FRAMESIZES` to detect supported | ||
| 128 | resolutions for a given format, passing the desired pixel format in | ||
| 129 | :c:type:`v4l2_frmsizeenum` ``pixel_format``. | ||
| 130 | |||
| 131 | * Values returned by :c:func:`VIDIOC_ENUM_FRAMESIZES` for a coded pixel | ||
| 132 | format will include all possible coded resolutions supported by the | ||
| 133 | encoder for the given coded pixel format. | ||
| 134 | |||
| 135 | * Values returned by :c:func:`VIDIOC_ENUM_FRAMESIZES` for a raw pixel format | ||
| 136 | will include all possible frame buffer resolutions supported by the | ||
| 137 | encoder for the given raw pixel format and coded format currently set on | ||
| 138 | ``CAPTURE``. | ||
| 139 | |||
| 140 | 4. The client may use :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` to detect supported | ||
| 141 | frame intervals for a given format and resolution, passing the desired pixel | ||
| 142 | format in :c:type:`v4l2_frmsizeenum` ``pixel_format`` and the resolution | ||
| 143 | in :c:type:`v4l2_frmsizeenum` ``width`` and :c:type:`v4l2_frmsizeenum` | ||
| 144 | ``height``. | ||
| 145 | |||
| 146 | * Values returned by :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` for a coded pixel | ||
| 147 | format and coded resolution will include all possible frame intervals | ||
| 148 | supported by the encoder for the given coded pixel format and resolution. | ||
| 149 | |||
| 150 | * Values returned by :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` for a raw pixel | ||
| 151 | format and resolution will include all possible frame intervals supported | ||
| 152 | by the encoder for the given raw pixel format and resolution and for the | ||
| 153 | coded format, coded resolution and coded frame interval currently set on | ||
| 154 | ``CAPTURE``. | ||
| 155 | |||
| 156 | * Support for :c:func:`VIDIOC_ENUM_FRAMEINTERVALS` is optional. If it is | ||
| 157 | not implemented, then there are no special restrictions other than the | ||
| 158 | limits of the codec itself. | ||
| 159 | |||
| 160 | 5. Supported profiles and levels for the coded format currently set on | ||
| 161 | ``CAPTURE``, if applicable, may be queried using their respective controls | ||
| 162 | via :c:func:`VIDIOC_QUERYCTRL`. | ||
| 163 | |||
| 164 | 6. Any additional encoder capabilities may be discovered by querying | ||
| 165 | their respective controls. | ||
| 166 | |||
| 167 | Initialization | ||
| 168 | ============== | ||
| 169 | |||
| 170 | 1. Set the coded format on the ``CAPTURE`` queue via :c:func:`VIDIOC_S_FMT`. | ||
| 171 | |||
| 172 | * **Required fields:** | ||
| 173 | |||
| 174 | ``type`` | ||
| 175 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. | ||
| 176 | |||
| 177 | ``pixelformat`` | ||
| 178 | the coded format to be produced. | ||
| 179 | |||
| 180 | ``sizeimage`` | ||
| 181 | desired size of ``CAPTURE`` buffers; the encoder may adjust it to | ||
| 182 | match hardware requirements. | ||
| 183 | |||
| 184 | ``width``, ``height`` | ||
| 185 | ignored (read-only). | ||
| 186 | |||
| 187 | other fields | ||
| 188 | follow standard semantics. | ||
| 189 | |||
| 190 | * **Return fields:** | ||
| 191 | |||
| 192 | ``sizeimage`` | ||
| 193 | adjusted size of ``CAPTURE`` buffers. | ||
| 194 | |||
| 195 | ``width``, ``height`` | ||
| 196 | the coded size selected by the encoder based on current state, e.g. | ||
| 197 | ``OUTPUT`` format, selection rectangles, etc. (read-only). | ||
| 198 | |||
| 199 | .. important:: | ||
| 200 | |||
| 201 | Changing the ``CAPTURE`` format may change the currently set ``OUTPUT`` | ||
| 202 | format. How the new ``OUTPUT`` format is determined is up to the encoder | ||
| 203 | and the client must ensure it matches its needs afterwards. | ||
| 204 | |||
| 205 | 2. **Optional.** Enumerate supported ``OUTPUT`` formats (raw formats for | ||
| 206 | source) for the selected coded format via :c:func:`VIDIOC_ENUM_FMT`. | ||
| 207 | |||
| 208 | * **Required fields:** | ||
| 209 | |||
| 210 | ``type`` | ||
| 211 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. | ||
| 212 | |||
| 213 | other fields | ||
| 214 | follow standard semantics. | ||
| 215 | |||
| 216 | * **Return fields:** | ||
| 217 | |||
| 218 | ``pixelformat`` | ||
| 219 | raw format supported for the coded format currently selected on | ||
| 220 | the ``CAPTURE`` queue. | ||
| 221 | |||
| 222 | other fields | ||
| 223 | follow standard semantics. | ||
| 224 | |||
| 225 | 3. Set the raw source format on the ``OUTPUT`` queue via | ||
| 226 | :c:func:`VIDIOC_S_FMT`. | ||
| 227 | |||
| 228 | * **Required fields:** | ||
| 229 | |||
| 230 | ``type`` | ||
| 231 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. | ||
| 232 | |||
| 233 | ``pixelformat`` | ||
| 234 | raw format of the source. | ||
| 235 | |||
| 236 | ``width``, ``height`` | ||
| 237 | source resolution. | ||
| 238 | |||
| 239 | other fields | ||
| 240 | follow standard semantics. | ||
| 241 | |||
| 242 | * **Return fields:** | ||
| 243 | |||
| 244 | ``width``, ``height`` | ||
| 245 | may be adjusted to match encoder minimums, maximums and alignment | ||
| 246 | requirements, as required by the currently selected formats, as | ||
| 247 | reported by :c:func:`VIDIOC_ENUM_FRAMESIZES`. | ||
| 248 | |||
| 249 | other fields | ||
| 250 | follow standard semantics. | ||
| 251 | |||
| 252 | * Setting the ``OUTPUT`` format will reset the selection rectangles to their | ||
| 253 | default values, based on the new resolution, as described in the next | ||
| 254 | step. | ||
| 255 | |||
| 256 | 4. Set the raw frame interval on the ``OUTPUT`` queue via | ||
| 257 | :c:func:`VIDIOC_S_PARM`. This also sets the coded frame interval on the | ||
| 258 | ``CAPTURE`` queue to the same value. | ||
| 259 | |||
| 260 | * ** Required fields:** | ||
| 261 | |||
| 262 | ``type`` | ||
| 263 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. | ||
| 264 | |||
| 265 | ``parm.output`` | ||
| 266 | set all fields except ``parm.output.timeperframe`` to 0. | ||
| 267 | |||
| 268 | ``parm.output.timeperframe`` | ||
| 269 | the desired frame interval; the encoder may adjust it to | ||
| 270 | match hardware requirements. | ||
| 271 | |||
| 272 | * **Return fields:** | ||
| 273 | |||
| 274 | ``parm.output.timeperframe`` | ||
| 275 | the adjusted frame interval. | ||
| 276 | |||
| 277 | .. important:: | ||
| 278 | |||
| 279 | Changing the ``OUTPUT`` frame interval *also* sets the framerate that | ||
| 280 | the encoder uses to encode the video. So setting the frame interval | ||
| 281 | to 1/24 (or 24 frames per second) will produce a coded video stream | ||
| 282 | that can be played back at that speed. The frame interval for the | ||
| 283 | ``OUTPUT`` queue is just a hint, the application may provide raw | ||
| 284 | frames at a different rate. It can be used by the driver to help | ||
| 285 | schedule multiple encoders running in parallel. | ||
| 286 | |||
| 287 | In the next step the ``CAPTURE`` frame interval can optionally be | ||
| 288 | changed to a different value. This is useful for off-line encoding | ||
| 289 | were the coded frame interval can be different from the rate at | ||
| 290 | which raw frames are supplied. | ||
| 291 | |||
| 292 | .. important:: | ||
| 293 | |||
| 294 | ``timeperframe`` deals with *frames*, not fields. So for interlaced | ||
| 295 | formats this is the time per two fields, since a frame consists of | ||
| 296 | a top and a bottom field. | ||
| 297 | |||
| 298 | .. note:: | ||
| 299 | |||
| 300 | It is due to historical reasons that changing the ``OUTPUT`` frame | ||
| 301 | interval also changes the coded frame interval on the ``CAPTURE`` | ||
| 302 | queue. Ideally these would be independent settings, but that would | ||
| 303 | break the existing API. | ||
| 304 | |||
| 305 | 5. **Optional** Set the coded frame interval on the ``CAPTURE`` queue via | ||
| 306 | :c:func:`VIDIOC_S_PARM`. This is only necessary if the coded frame | ||
| 307 | interval is different from the raw frame interval, which is typically | ||
| 308 | the case for off-line encoding. Support for this feature is signalled | ||
| 309 | by the :ref:`V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL <fmtdesc-flags>` format flag. | ||
| 310 | |||
| 311 | * ** Required fields:** | ||
| 312 | |||
| 313 | ``type`` | ||
| 314 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. | ||
| 315 | |||
| 316 | ``parm.capture`` | ||
| 317 | set all fields except ``parm.capture.timeperframe`` to 0. | ||
| 318 | |||
| 319 | ``parm.capture.timeperframe`` | ||
| 320 | the desired coded frame interval; the encoder may adjust it to | ||
| 321 | match hardware requirements. | ||
| 322 | |||
| 323 | * **Return fields:** | ||
| 324 | |||
| 325 | ``parm.capture.timeperframe`` | ||
| 326 | the adjusted frame interval. | ||
| 327 | |||
| 328 | .. important:: | ||
| 329 | |||
| 330 | Changing the ``CAPTURE`` frame interval sets the framerate for the | ||
| 331 | coded video. It does *not* set the rate at which buffers arrive on the | ||
| 332 | ``CAPTURE`` queue, that depends on how fast the encoder is and how | ||
| 333 | fast raw frames are queued on the ``OUTPUT`` queue. | ||
| 334 | |||
| 335 | .. important:: | ||
| 336 | |||
| 337 | ``timeperframe`` deals with *frames*, not fields. So for interlaced | ||
| 338 | formats this is the time per two fields, since a frame consists of | ||
| 339 | a top and a bottom field. | ||
| 340 | |||
| 341 | .. note:: | ||
| 342 | |||
| 343 | Not all drivers support this functionality, in that case just set | ||
| 344 | the desired coded frame interval for the ``OUTPUT`` queue. | ||
| 345 | |||
| 346 | However, drivers that can schedule multiple encoders based on the | ||
| 347 | ``OUTPUT`` frame interval must support this optional feature. | ||
| 348 | |||
| 349 | 6. **Optional.** Set the visible resolution for the stream metadata via | ||
| 350 | :c:func:`VIDIOC_S_SELECTION` on the ``OUTPUT`` queue if it is desired | ||
| 351 | to be different than the full OUTPUT resolution. | ||
| 352 | |||
| 353 | * **Required fields:** | ||
| 354 | |||
| 355 | ``type`` | ||
| 356 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. | ||
| 357 | |||
| 358 | ``target`` | ||
| 359 | set to ``V4L2_SEL_TGT_CROP``. | ||
| 360 | |||
| 361 | ``r.left``, ``r.top``, ``r.width``, ``r.height`` | ||
| 362 | visible rectangle; this must fit within the `V4L2_SEL_TGT_CROP_BOUNDS` | ||
| 363 | rectangle and may be subject to adjustment to match codec and | ||
| 364 | hardware constraints. | ||
| 365 | |||
| 366 | * **Return fields:** | ||
| 367 | |||
| 368 | ``r.left``, ``r.top``, ``r.width``, ``r.height`` | ||
| 369 | visible rectangle adjusted by the encoder. | ||
| 370 | |||
| 371 | * The following selection targets are supported on ``OUTPUT``: | ||
| 372 | |||
| 373 | ``V4L2_SEL_TGT_CROP_BOUNDS`` | ||
| 374 | equal to the full source frame, matching the active ``OUTPUT`` | ||
| 375 | format. | ||
| 376 | |||
| 377 | ``V4L2_SEL_TGT_CROP_DEFAULT`` | ||
| 378 | equal to ``V4L2_SEL_TGT_CROP_BOUNDS``. | ||
| 379 | |||
| 380 | ``V4L2_SEL_TGT_CROP`` | ||
| 381 | rectangle within the source buffer to be encoded into the | ||
| 382 | ``CAPTURE`` stream; defaults to ``V4L2_SEL_TGT_CROP_DEFAULT``. | ||
| 383 | |||
| 384 | .. note:: | ||
| 385 | |||
| 386 | A common use case for this selection target is encoding a source | ||
| 387 | video with a resolution that is not a multiple of a macroblock, | ||
| 388 | e.g. the common 1920x1080 resolution may require the source | ||
| 389 | buffers to be aligned to 1920x1088 for codecs with 16x16 macroblock | ||
| 390 | size. To avoid encoding the padding, the client needs to explicitly | ||
| 391 | configure this selection target to 1920x1080. | ||
| 392 | |||
| 393 | .. warning:: | ||
| 394 | |||
| 395 | The encoder may adjust the crop/compose rectangles to the nearest | ||
| 396 | supported ones to meet codec and hardware requirements. The client needs | ||
| 397 | to check the adjusted rectangle returned by :c:func:`VIDIOC_S_SELECTION`. | ||
| 398 | |||
| 399 | 7. Allocate buffers for both ``OUTPUT`` and ``CAPTURE`` via | ||
| 400 | :c:func:`VIDIOC_REQBUFS`. This may be performed in any order. | ||
| 401 | |||
| 402 | * **Required fields:** | ||
| 403 | |||
| 404 | ``count`` | ||
| 405 | requested number of buffers to allocate; greater than zero. | ||
| 406 | |||
| 407 | ``type`` | ||
| 408 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT`` or | ||
| 409 | ``CAPTURE``. | ||
| 410 | |||
| 411 | other fields | ||
| 412 | follow standard semantics. | ||
| 413 | |||
| 414 | * **Return fields:** | ||
| 415 | |||
| 416 | ``count`` | ||
| 417 | actual number of buffers allocated. | ||
| 418 | |||
| 419 | .. warning:: | ||
| 420 | |||
| 421 | The actual number of allocated buffers may differ from the ``count`` | ||
| 422 | given. The client must check the updated value of ``count`` after the | ||
| 423 | call returns. | ||
| 424 | |||
| 425 | .. note:: | ||
| 426 | |||
| 427 | To allocate more than the minimum number of OUTPUT buffers (for pipeline | ||
| 428 | depth), the client may query the ``V4L2_CID_MIN_BUFFERS_FOR_OUTPUT`` | ||
| 429 | control to get the minimum number of buffers required, and pass the | ||
| 430 | obtained value plus the number of additional buffers needed in the | ||
| 431 | ``count`` field to :c:func:`VIDIOC_REQBUFS`. | ||
| 432 | |||
| 433 | Alternatively, :c:func:`VIDIOC_CREATE_BUFS` can be used to have more | ||
| 434 | control over buffer allocation. | ||
| 435 | |||
| 436 | * **Required fields:** | ||
| 437 | |||
| 438 | ``count`` | ||
| 439 | requested number of buffers to allocate; greater than zero. | ||
| 440 | |||
| 441 | ``type`` | ||
| 442 | a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. | ||
| 443 | |||
| 444 | other fields | ||
| 445 | follow standard semantics. | ||
| 446 | |||
| 447 | * **Return fields:** | ||
| 448 | |||
| 449 | ``count`` | ||
| 450 | adjusted to the number of allocated buffers. | ||
| 451 | |||
| 452 | 8. Begin streaming on both ``OUTPUT`` and ``CAPTURE`` queues via | ||
| 453 | :c:func:`VIDIOC_STREAMON`. This may be performed in any order. The actual | ||
| 454 | encoding process starts when both queues start streaming. | ||
| 455 | |||
| 456 | .. note:: | ||
| 457 | |||
| 458 | If the client stops the ``CAPTURE`` queue during the encode process and then | ||
| 459 | restarts it again, the encoder will begin generating a stream independent | ||
| 460 | from the stream generated before the stop. The exact constraints depend | ||
| 461 | on the coded format, but may include the following implications: | ||
| 462 | |||
| 463 | * encoded frames produced after the restart must not reference any | ||
| 464 | frames produced before the stop, e.g. no long term references for | ||
| 465 | H.264/HEVC, | ||
| 466 | |||
| 467 | * any headers that must be included in a standalone stream must be | ||
| 468 | produced again, e.g. SPS and PPS for H.264/HEVC. | ||
| 469 | |||
| 470 | Encoding | ||
| 471 | ======== | ||
| 472 | |||
| 473 | This state is reached after the `Initialization` sequence finishes | ||
| 474 | successfully. In this state, the client queues and dequeues buffers to both | ||
| 475 | queues via :c:func:`VIDIOC_QBUF` and :c:func:`VIDIOC_DQBUF`, following the | ||
| 476 | standard semantics. | ||
| 477 | |||
| 478 | The content of encoded ``CAPTURE`` buffers depends on the active coded pixel | ||
| 479 | format and may be affected by codec-specific extended controls, as stated | ||
| 480 | in the documentation of each format. | ||
| 481 | |||
| 482 | Both queues operate independently, following standard behavior of V4L2 buffer | ||
| 483 | queues and memory-to-memory devices. In addition, the order of encoded frames | ||
| 484 | dequeued from the ``CAPTURE`` queue may differ from the order of queuing raw | ||
| 485 | frames to the ``OUTPUT`` queue, due to properties of the selected coded format, | ||
| 486 | e.g. frame reordering. | ||
| 487 | |||
| 488 | The client must not assume any direct relationship between ``CAPTURE`` and | ||
| 489 | ``OUTPUT`` buffers and any specific timing of buffers becoming | ||
| 490 | available to dequeue. Specifically: | ||
| 491 | |||
| 492 | * a buffer queued to ``OUTPUT`` may result in more than one buffer produced on | ||
| 493 | ``CAPTURE`` (for example, if returning an encoded frame allowed the encoder | ||
| 494 | to return a frame that preceded it in display, but succeeded it in the decode | ||
| 495 | order; however, there may be other reasons for this as well), | ||
| 496 | |||
| 497 | * a buffer queued to ``OUTPUT`` may result in a buffer being produced on | ||
| 498 | ``CAPTURE`` later into encode process, and/or after processing further | ||
| 499 | ``OUTPUT`` buffers, or be returned out of order, e.g. if display | ||
| 500 | reordering is used, | ||
| 501 | |||
| 502 | * buffers may become available on the ``CAPTURE`` queue without additional | ||
| 503 | buffers queued to ``OUTPUT`` (e.g. during drain or ``EOS``), because of the | ||
| 504 | ``OUTPUT`` buffers queued in the past whose encoding results are only | ||
| 505 | available at later time, due to specifics of the encoding process, | ||
| 506 | |||
| 507 | * buffers queued to ``OUTPUT`` may not become available to dequeue instantly | ||
| 508 | after being encoded into a corresponding ``CAPTURE`` buffer, e.g. if the | ||
| 509 | encoder needs to use the frame as a reference for encoding further frames. | ||
| 510 | |||
| 511 | .. note:: | ||
| 512 | |||
| 513 | To allow matching encoded ``CAPTURE`` buffers with ``OUTPUT`` buffers they | ||
| 514 | originated from, the client can set the ``timestamp`` field of the | ||
| 515 | :c:type:`v4l2_buffer` struct when queuing an ``OUTPUT`` buffer. The | ||
| 516 | ``CAPTURE`` buffer(s), which resulted from encoding that ``OUTPUT`` buffer | ||
| 517 | will have their ``timestamp`` field set to the same value when dequeued. | ||
| 518 | |||
| 519 | In addition to the straightforward case of one ``OUTPUT`` buffer producing | ||
| 520 | one ``CAPTURE`` buffer, the following cases are defined: | ||
| 521 | |||
| 522 | * one ``OUTPUT`` buffer generates multiple ``CAPTURE`` buffers: the same | ||
| 523 | ``OUTPUT`` timestamp will be copied to multiple ``CAPTURE`` buffers, | ||
| 524 | |||
| 525 | * the encoding order differs from the presentation order (i.e. the | ||
| 526 | ``CAPTURE`` buffers are out-of-order compared to the ``OUTPUT`` buffers): | ||
| 527 | ``CAPTURE`` timestamps will not retain the order of ``OUTPUT`` timestamps. | ||
| 528 | |||
| 529 | .. note:: | ||
| 530 | |||
| 531 | To let the client distinguish between frame types (keyframes, intermediate | ||
| 532 | frames; the exact list of types depends on the coded format), the | ||
| 533 | ``CAPTURE`` buffers will have corresponding flag bits set in their | ||
| 534 | :c:type:`v4l2_buffer` struct when dequeued. See the documentation of | ||
| 535 | :c:type:`v4l2_buffer` and each coded pixel format for exact list of flags | ||
| 536 | and their meanings. | ||
| 537 | |||
| 538 | Should an encoding error occur, it will be reported to the client with the level | ||
| 539 | of details depending on the encoder capabilities. Specifically: | ||
| 540 | |||
| 541 | * the ``CAPTURE`` buffer (if any) that contains the results of the failed encode | ||
| 542 | operation will be returned with the ``V4L2_BUF_FLAG_ERROR`` flag set, | ||
| 543 | |||
| 544 | * if the encoder is able to precisely report the ``OUTPUT`` buffer(s) that triggered | ||
| 545 | the error, such buffer(s) will be returned with the ``V4L2_BUF_FLAG_ERROR`` flag | ||
| 546 | set. | ||
| 547 | |||
| 548 | .. note:: | ||
| 549 | |||
| 550 | If a ``CAPTURE`` buffer is too small then it is just returned with the | ||
| 551 | ``V4L2_BUF_FLAG_ERROR`` flag set. More work is needed to detect that this | ||
| 552 | error occurred because the buffer was too small, and to provide support to | ||
| 553 | free existing buffers that were too small. | ||
| 554 | |||
| 555 | In case of a fatal failure that does not allow the encoding to continue, any | ||
| 556 | further operations on corresponding encoder file handle will return the -EIO | ||
| 557 | error code. The client may close the file handle and open a new one, or | ||
| 558 | alternatively reinitialize the instance by stopping streaming on both queues, | ||
| 559 | releasing all buffers and performing the Initialization sequence again. | ||
| 560 | |||
| 561 | Encoding Parameter Changes | ||
| 562 | ========================== | ||
| 563 | |||
| 564 | The client is allowed to use :c:func:`VIDIOC_S_CTRL` to change encoder | ||
| 565 | parameters at any time. The availability of parameters is encoder-specific | ||
| 566 | and the client must query the encoder to find the set of available controls. | ||
| 567 | |||
| 568 | The ability to change each parameter during encoding is encoder-specific, as | ||
| 569 | per the standard semantics of the V4L2 control interface. The client may | ||
| 570 | attempt to set a control during encoding and if the operation fails with the | ||
| 571 | -EBUSY error code, the ``CAPTURE`` queue needs to be stopped for the | ||
| 572 | configuration change to be allowed. To do this, it may follow the `Drain` | ||
| 573 | sequence to avoid losing the already queued/encoded frames. | ||
| 574 | |||
| 575 | The timing of parameter updates is encoder-specific, as per the standard | ||
| 576 | semantics of the V4L2 control interface. If the client needs to apply the | ||
| 577 | parameters exactly at specific frame, using the Request API | ||
| 578 | (:ref:`media-request-api`) should be considered, if supported by the encoder. | ||
| 579 | |||
| 580 | Drain | ||
| 581 | ===== | ||
| 582 | |||
| 583 | To ensure that all the queued ``OUTPUT`` buffers have been processed and the | ||
| 584 | related ``CAPTURE`` buffers are given to the client, the client must follow the | ||
| 585 | drain sequence described below. After the drain sequence ends, the client has | ||
| 586 | received all encoded frames for all ``OUTPUT`` buffers queued before the | ||
| 587 | sequence was started. | ||
| 588 | |||
| 589 | 1. Begin the drain sequence by issuing :c:func:`VIDIOC_ENCODER_CMD`. | ||
| 590 | |||
| 591 | * **Required fields:** | ||
| 592 | |||
| 593 | ``cmd`` | ||
| 594 | set to ``V4L2_ENC_CMD_STOP``. | ||
| 595 | |||
| 596 | ``flags`` | ||
| 597 | set to 0. | ||
| 598 | |||
| 599 | ``pts`` | ||
| 600 | set to 0. | ||
| 601 | |||
| 602 | .. warning:: | ||
| 603 | |||
| 604 | The sequence can be only initiated if both ``OUTPUT`` and ``CAPTURE`` | ||
| 605 | queues are streaming. For compatibility reasons, the call to | ||
| 606 | :c:func:`VIDIOC_ENCODER_CMD` will not fail even if any of the queues is | ||
| 607 | not streaming, but at the same time it will not initiate the `Drain` | ||
| 608 | sequence and so the steps described below would not be applicable. | ||
| 609 | |||
| 610 | 2. Any ``OUTPUT`` buffers queued by the client before the | ||
| 611 | :c:func:`VIDIOC_ENCODER_CMD` was issued will be processed and encoded as | ||
| 612 | normal. The client must continue to handle both queues independently, | ||
| 613 | similarly to normal encode operation. This includes: | ||
| 614 | |||
| 615 | * queuing and dequeuing ``CAPTURE`` buffers, until a buffer marked with the | ||
| 616 | ``V4L2_BUF_FLAG_LAST`` flag is dequeued, | ||
| 617 | |||
| 618 | .. warning:: | ||
| 619 | |||
| 620 | The last buffer may be empty (with :c:type:`v4l2_buffer` | ||
| 621 | ``bytesused`` = 0) and in that case it must be ignored by the client, | ||
| 622 | as it does not contain an encoded frame. | ||
| 623 | |||
| 624 | .. note:: | ||
| 625 | |||
| 626 | Any attempt to dequeue more ``CAPTURE`` buffers beyond the buffer | ||
| 627 | marked with ``V4L2_BUF_FLAG_LAST`` will result in a -EPIPE error from | ||
| 628 | :c:func:`VIDIOC_DQBUF`. | ||
| 629 | |||
| 630 | * dequeuing processed ``OUTPUT`` buffers, until all the buffers queued | ||
| 631 | before the ``V4L2_ENC_CMD_STOP`` command are dequeued, | ||
| 632 | |||
| 633 | * dequeuing the ``V4L2_EVENT_EOS`` event, if the client subscribes to it. | ||
| 634 | |||
| 635 | .. note:: | ||
| 636 | |||
| 637 | For backwards compatibility, the encoder will signal a ``V4L2_EVENT_EOS`` | ||
| 638 | event when the last frame has been encoded and all frames are ready to be | ||
| 639 | dequeued. It is deprecated behavior and the client must not rely on it. | ||
| 640 | The ``V4L2_BUF_FLAG_LAST`` buffer flag should be used instead. | ||
| 641 | |||
| 642 | 3. Once all ``OUTPUT`` buffers queued before the ``V4L2_ENC_CMD_STOP`` call are | ||
| 643 | dequeued and the last ``CAPTURE`` buffer is dequeued, the encoder is stopped | ||
| 644 | and it will accept, but not process any newly queued ``OUTPUT`` buffers | ||
| 645 | until the client issues any of the following operations: | ||
| 646 | |||
| 647 | * ``V4L2_ENC_CMD_START`` - the encoder will not be reset and will resume | ||
| 648 | operation normally, with all the state from before the drain, | ||
| 649 | |||
| 650 | * a pair of :c:func:`VIDIOC_STREAMOFF` and :c:func:`VIDIOC_STREAMON` on the | ||
| 651 | ``CAPTURE`` queue - the encoder will be reset (see the `Reset` sequence) | ||
| 652 | and then resume encoding, | ||
| 653 | |||
| 654 | * a pair of :c:func:`VIDIOC_STREAMOFF` and :c:func:`VIDIOC_STREAMON` on the | ||
| 655 | ``OUTPUT`` queue - the encoder will resume operation normally, however any | ||
| 656 | source frames queued to the ``OUTPUT`` queue between ``V4L2_ENC_CMD_STOP`` | ||
| 657 | and :c:func:`VIDIOC_STREAMOFF` will be discarded. | ||
| 658 | |||
| 659 | .. note:: | ||
| 660 | |||
| 661 | Once the drain sequence is initiated, the client needs to drive it to | ||
| 662 | completion, as described by the steps above, unless it aborts the process by | ||
| 663 | issuing :c:func:`VIDIOC_STREAMOFF` on any of the ``OUTPUT`` or ``CAPTURE`` | ||
| 664 | queues. The client is not allowed to issue ``V4L2_ENC_CMD_START`` or | ||
| 665 | ``V4L2_ENC_CMD_STOP`` again while the drain sequence is in progress and they | ||
| 666 | will fail with -EBUSY error code if attempted. | ||
| 667 | |||
| 668 | For reference, handling of various corner cases is described below: | ||
| 669 | |||
| 670 | * In case of no buffer in the ``OUTPUT`` queue at the time the | ||
| 671 | ``V4L2_ENC_CMD_STOP`` command was issued, the drain sequence completes | ||
| 672 | immediately and the encoder returns an empty ``CAPTURE`` buffer with the | ||
| 673 | ``V4L2_BUF_FLAG_LAST`` flag set. | ||
| 674 | |||
| 675 | * In case of no buffer in the ``CAPTURE`` queue at the time the drain | ||
| 676 | sequence completes, the next time the client queues a ``CAPTURE`` buffer | ||
| 677 | it is returned at once as an empty buffer with the ``V4L2_BUF_FLAG_LAST`` | ||
| 678 | flag set. | ||
| 679 | |||
| 680 | * If :c:func:`VIDIOC_STREAMOFF` is called on the ``CAPTURE`` queue in the | ||
| 681 | middle of the drain sequence, the drain sequence is canceled and all | ||
| 682 | ``CAPTURE`` buffers are implicitly returned to the client. | ||
| 683 | |||
| 684 | * If :c:func:`VIDIOC_STREAMOFF` is called on the ``OUTPUT`` queue in the | ||
| 685 | middle of the drain sequence, the drain sequence completes immediately and | ||
| 686 | next ``CAPTURE`` buffer will be returned empty with the | ||
| 687 | ``V4L2_BUF_FLAG_LAST`` flag set. | ||
| 688 | |||
| 689 | Although not mandatory, the availability of encoder commands may be queried | ||
| 690 | using :c:func:`VIDIOC_TRY_ENCODER_CMD`. | ||
| 691 | |||
| 692 | Reset | ||
| 693 | ===== | ||
| 694 | |||
| 695 | The client may want to request the encoder to reinitialize the encoding, so | ||
| 696 | that the following stream data becomes independent from the stream data | ||
| 697 | generated before. Depending on the coded format, that may imply that: | ||
| 698 | |||
| 699 | * encoded frames produced after the restart must not reference any frames | ||
| 700 | produced before the stop, e.g. no long term references for H.264/HEVC, | ||
| 701 | |||
| 702 | * any headers that must be included in a standalone stream must be produced | ||
| 703 | again, e.g. SPS and PPS for H.264/HEVC. | ||
| 704 | |||
| 705 | This can be achieved by performing the reset sequence. | ||
| 706 | |||
| 707 | 1. Perform the `Drain` sequence to ensure all the in-flight encoding finishes | ||
| 708 | and respective buffers are dequeued. | ||
| 709 | |||
| 710 | 2. Stop streaming on the ``CAPTURE`` queue via :c:func:`VIDIOC_STREAMOFF`. This | ||
| 711 | will return all currently queued ``CAPTURE`` buffers to the client, without | ||
| 712 | valid frame data. | ||
| 713 | |||
| 714 | 3. Start streaming on the ``CAPTURE`` queue via :c:func:`VIDIOC_STREAMON` and | ||
| 715 | continue with regular encoding sequence. The encoded frames produced into | ||
| 716 | ``CAPTURE`` buffers from now on will contain a standalone stream that can be | ||
| 717 | decoded without the need for frames encoded before the reset sequence, | ||
| 718 | starting at the first ``OUTPUT`` buffer queued after issuing the | ||
| 719 | `V4L2_ENC_CMD_STOP` of the `Drain` sequence. | ||
| 720 | |||
| 721 | This sequence may be also used to change encoding parameters for encoders | ||
| 722 | without the ability to change the parameters on the fly. | ||
| 723 | |||
| 724 | Commit Points | ||
| 725 | ============= | ||
| 726 | |||
| 727 | Setting formats and allocating buffers triggers changes in the behavior of the | ||
| 728 | encoder. | ||
| 729 | |||
| 730 | 1. Setting the format on the ``CAPTURE`` queue may change the set of formats | ||
| 731 | supported/advertised on the ``OUTPUT`` queue. In particular, it also means | ||
| 732 | that the ``OUTPUT`` format may be reset and the client must not rely on the | ||
| 733 | previously set format being preserved. | ||
| 734 | |||
| 735 | 2. Enumerating formats on the ``OUTPUT`` queue always returns only formats | ||
| 736 | supported for the current ``CAPTURE`` format. | ||
| 737 | |||
| 738 | 3. Setting the format on the ``OUTPUT`` queue does not change the list of | ||
| 739 | formats available on the ``CAPTURE`` queue. An attempt to set the ``OUTPUT`` | ||
| 740 | format that is not supported for the currently selected ``CAPTURE`` format | ||
| 741 | will result in the encoder adjusting the requested ``OUTPUT`` format to a | ||
| 742 | supported one. | ||
| 743 | |||
| 744 | 4. Enumerating formats on the ``CAPTURE`` queue always returns the full set of | ||
| 745 | supported coded formats, irrespective of the current ``OUTPUT`` format. | ||
| 746 | |||
| 747 | 5. While buffers are allocated on any of the ``OUTPUT`` or ``CAPTURE`` queues, | ||
| 748 | the client must not change the format on the ``CAPTURE`` queue. Drivers will | ||
| 749 | return the -EBUSY error code for any such format change attempt. | ||
| 750 | |||
| 751 | To summarize, setting formats and allocation must always start with the | ||
| 752 | ``CAPTURE`` queue and the ``CAPTURE`` queue is the master that governs the | ||
| 753 | set of supported formats for the ``OUTPUT`` queue. | ||
| @@ -46,4 +46,5 @@ devices are given in the following sections. · 45 unmodified lines | |||
| 46 | :maxdepth: 1 | 46 | :maxdepth: 1 |
| 47 | 47 | ||
| 48 | dev-decoder | 48 | dev-decoder |
| 49 | dev-encoder | ||
| 49 | dev-stateless-decoder | 50 | dev-stateless-decoder |
| @@ -51,7 +51,7 @@ other information, the physical address of the framebuffer in the · 50 unmodified lines | |||
| 51 | ``base`` field of struct :c:type:`v4l2_framebuffer`. | 51 | ``base`` field of struct :c:type:`v4l2_framebuffer`. |
| 52 | The framebuffer device ioctl ``FBIOGET_FSCREENINFO`` returns the same | 52 | The framebuffer device ioctl ``FBIOGET_FSCREENINFO`` returns the same |
| 53 | address in the ``smem_start`` field of struct | 53 | address in the ``smem_start`` field of struct |
| 54 | struct :c:type:`fb_fix_screeninfo`. The ``FBIOGET_FSCREENINFO`` | 54 | :c:type:`fb_fix_screeninfo`. The ``FBIOGET_FSCREENINFO`` |
| 55 | ioctl and struct :c:type:`fb_fix_screeninfo` are defined in | 55 | ioctl and struct :c:type:`fb_fix_screeninfo` are defined in |
| 56 | the ``linux/fb.h`` header file. | 56 | the ``linux/fb.h`` header file. |
| 57 | 57 | ||
| @@ -78,7 +78,7 @@ field of a struct :c:type:`v4l2_format` to · 77 unmodified lines | |||
| 78 | ``V4L2_BUF_TYPE_SDR_CAPTURE`` or ``V4L2_BUF_TYPE_SDR_OUTPUT`` and use | 78 | ``V4L2_BUF_TYPE_SDR_CAPTURE`` or ``V4L2_BUF_TYPE_SDR_OUTPUT`` and use |
| 79 | the struct :c:type:`v4l2_sdr_format` ``sdr`` member | 79 | the struct :c:type:`v4l2_sdr_format` ``sdr`` member |
| 80 | of the ``fmt`` union as needed per the desired operation. Currently | 80 | of the ``fmt`` union as needed per the desired operation. Currently |
| 81 | there is two fields, ``pixelformat`` and ``buffersize``, of struct | 81 | there are two fields, ``pixelformat`` and ``buffersize``, of |
| 82 | struct :c:type:`v4l2_sdr_format` which are used. | 82 | struct :c:type:`v4l2_sdr_format` which are used. |
| 83 | Content of the ``pixelformat`` is V4L2 FourCC code of the data format. | 83 | Content of the ``pixelformat`` is V4L2 FourCC code of the data format. |
| 84 | The ``buffersize`` field is maximum buffer size in bytes required for | 84 | The ``buffersize`` field is maximum buffer size in bytes required for |
| @@ -43,7 +43,7 @@ transmission arguments. · 42 unmodified lines | |||
| 43 | 1998-09-28: Revamped video standard. Made video controls individually | 43 | 1998-09-28: Revamped video standard. Made video controls individually |
| 44 | enumerable. | 44 | enumerable. |
| 45 | 45 | ||
| 46 | 1998-10-02: The ``id`` field was removed from struct | 46 | 1998-10-02: The ``id`` field was removed from |
| 47 | struct ``video_standard`` and the color subcarrier fields were | 47 | struct ``video_standard`` and the color subcarrier fields were |
| 48 | renamed. The :ref:`VIDIOC_QUERYSTD` ioctl was | 48 | renamed. The :ref:`VIDIOC_QUERYSTD` ioctl was |
| 49 | renamed to :ref:`VIDIOC_ENUMSTD`, | 49 | renamed to :ref:`VIDIOC_ENUMSTD`, |
| @@ -260,7 +260,7 @@ multiple tuners into account.) · 210 unmodified lines | |||
| 260 | 260 | ||
| 261 | 2000-09-18: ``V4L2_BUF_TYPE_VBI`` was added. This may *break | 261 | 2000-09-18: ``V4L2_BUF_TYPE_VBI`` was added. This may *break |
| 262 | compatibility* as the :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` and | 262 | compatibility* as the :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` and |
| 263 | :ref:`VIDIOC_S_FMT <VIDIOC_G_FMT>` ioctls may fail now if the struct | 263 | :ref:`VIDIOC_S_FMT <VIDIOC_G_FMT>` ioctls may fail now if the |
| 264 | struct ``v4l2_fmt`` ``type`` field does not contain | 264 | struct ``v4l2_fmt`` ``type`` field does not contain |
| 265 | ``V4L2_BUF_TYPE_VBI``. In the documentation of the struct | 265 | ``V4L2_BUF_TYPE_VBI``. In the documentation of the struct |
| 266 | :c:type:`v4l2_vbi_format` ``offset`` field the | 266 | :c:type:`v4l2_vbi_format` ``offset`` field the |
| @@ -69,37 +69,37 @@ Each cell is one byte. · 68 unmodified lines | |||
| 69 | 69 | ||
| 70 | B\ :sub:`00low bits 5--0`\ (bits 5--0) | 70 | B\ :sub:`00low bits 5--0`\ (bits 5--0) |
| 71 | 71 | ||
| 72 | - R\ :sub:`02low bits 3--0`\ (bits 7--4) | 72 | - B\ :sub:`02low bits 3--0`\ (bits 7--4) |
| 73 | 73 | ||
| 74 | G\ :sub:`01low bits 5--2`\ (bits 3--0) | 74 | G\ :sub:`01low bits 5--2`\ (bits 3--0) |
| 75 | 75 | ||
| 76 | - G\ :sub:`03low bits 5--0`\ (bits 7--2) | 76 | - G\ :sub:`03low bits 5--0`\ (bits 7--2) |
| 77 | 77 | ||
| 78 | R\ :sub:`02low bits 5--4`\ (bits 1--0) | 78 | B\ :sub:`02low bits 5--4`\ (bits 1--0) |
| 79 | 79 | ||
| 80 | - .. row 2 | 80 | - .. row 2 |
| 81 | 81 | ||
| 82 | - start + 7 | 82 | - start + 7 |
| 83 | 83 | ||
| 84 | - G\ :sub:`00high` | 84 | - G\ :sub:`10high` |
| 85 | 85 | ||
| 86 | - R\ :sub:`01high` | 86 | - R\ :sub:`11high` |
| 87 | 87 | ||
| 88 | - G\ :sub:`02high` | 88 | - G\ :sub:`12high` |
| 89 | 89 | ||
| 90 | - R\ :sub:`03high` | 90 | - R\ :sub:`13high` |
| 91 | 91 | ||
| 92 | - R\ :sub:`01low bits 1--0`\ (bits 7--6) | 92 | - R\ :sub:`11low bits 1--0`\ (bits 7--6) |
| 93 | 93 | ||
| 94 | G\ :sub:`00low bits 5--0`\ (bits 5--0) | 94 | G\ :sub:`10low bits 5--0`\ (bits 5--0) |
| 95 | 95 | ||
| 96 | - G\ :sub:`02low bits 3--0`\ (bits 7--4) | 96 | - G\ :sub:`12low bits 3--0`\ (bits 7--4) |
| 97 | 97 | ||
| 98 | R\ :sub:`01low bits 5--2`\ (bits 3--0) | 98 | R\ :sub:`11low bits 5--2`\ (bits 3--0) |
| 99 | 99 | ||
| 100 | - R\ :sub:`03low bits 5--0`\ (bits 7--2) | 100 | - R\ :sub:`13low bits 5--0`\ (bits 7--2) |
| 101 | 101 | ||
| 102 | G\ :sub:`02low bits 5--4`\ (bits 1--0) | 102 | G\ :sub:`12low bits 5--4`\ (bits 1--0) |
| 103 | 103 | ||
| 104 | - .. row 3 | 104 | - .. row 3 |
| 105 | 105 | ||
| @@ -117,13 +117,13 @@ Each cell is one byte. · 11 unmodified lines | |||
| 117 | 117 | ||
| 118 | B\ :sub:`20low bits 5--0`\ (bits 5--0) | 118 | B\ :sub:`20low bits 5--0`\ (bits 5--0) |
| 119 | 119 | ||
| 120 | - R\ :sub:`22low bits 3--0`\ (bits 7--4) | 120 | - B\ :sub:`22low bits 3--0`\ (bits 7--4) |
| 121 | 121 | ||
| 122 | G\ :sub:`21low bits 5--2`\ (bits 3--0) | 122 | G\ :sub:`21low bits 5--2`\ (bits 3--0) |
| 123 | 123 | ||
| 124 | - G\ :sub:`23low bits 5--0`\ (bits 7--2) | 124 | - G\ :sub:`23low bits 5--0`\ (bits 7--2) |
| 125 | 125 | ||
| 126 | R\ :sub:`22low bits 5--4`\ (bits 1--0) | 126 | B\ :sub:`22low bits 5--4`\ (bits 1--0) |
| 127 | 127 | ||
| 128 | - .. row 4 | 128 | - .. row 4 |
| 129 | 129 | ||
| @@ -44,6 +44,11 @@ Single-planar format structure · 43 unmodified lines | |||
| 44 | inside the stream, when fed to a stateful mem2mem decoder, the fields | 44 | inside the stream, when fed to a stateful mem2mem decoder, the fields |
| 45 | may be zero to rely on the decoder to detect the right values. For more | 45 | may be zero to rely on the decoder to detect the right values. For more |
| 46 | details see :ref:`decoder` and format descriptions. | 46 | details see :ref:`decoder` and format descriptions. |
| 47 | |||
| 48 | For compressed formats on the CAPTURE side of a stateful mem2mem | ||
| 49 | encoder, the fields must be zero, since the coded size is expected to | ||
| 50 | be calculated internally by the encoder itself, based on the OUTPUT | ||
| 51 | side. For more details see :ref:`encoder` and format descriptions. | ||
| 47 | * - __u32 | 52 | * - __u32 |
| 48 | - ``pixelformat`` | 53 | - ``pixelformat`` |
| 49 | - The pixel format or type of compression, set by the application. | 54 | - The pixel format or type of compression, set by the application. |
| @@ -63,6 +63,7 @@ Authors, in alphabetical order: · 62 unmodified lines | |||
| 63 | - Figa, Tomasz <tfiga@chromium.org> | 63 | - Figa, Tomasz <tfiga@chromium.org> |
| 64 | 64 | ||
| 65 | - Documented the memory-to-memory decoder interface. | 65 | - Documented the memory-to-memory decoder interface. |
| 66 | - Documented the memory-to-memory encoder interface. | ||
| 66 | 67 | ||
| 67 | - H Schimek, Michael <mschimek@gmx.at> | 68 | - H Schimek, Michael <mschimek@gmx.at> |
| 68 | 69 | ||
| @@ -75,6 +76,7 @@ Authors, in alphabetical order: · 6 unmodified lines | |||
| 75 | - Osciak, Pawel <posciak@chromium.org> | 76 | - Osciak, Pawel <posciak@chromium.org> |
| 76 | 77 | ||
| 77 | - Documented the memory-to-memory decoder interface. | 78 | - Documented the memory-to-memory decoder interface. |
| 79 | - Documented the memory-to-memory encoder interface. | ||
| 78 | 80 | ||
| 79 | - Osciak, Pawel <pawel@osciak.com> | 81 | - Osciak, Pawel <pawel@osciak.com> |
| 80 | 82 | ||
| @@ -121,7 +121,12 @@ than the number requested. · 120 unmodified lines | |||
| 121 | other changes, then set ``count`` to 0, ``memory`` to | 121 | other changes, then set ``count`` to 0, ``memory`` to |
| 122 | ``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type. | 122 | ``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type. |
| 123 | * - __u32 | 123 | * - __u32 |
| 124 | - ``reserved``\ [7] | 124 | - ``flags`` |
| 125 | - Specifies additional buffer management attributes. | ||
| 126 | See :ref:`memory-flags`. | ||
| 127 | |||
| 128 | * - __u32 | ||
| 129 | - ``reserved``\ [6] | ||
| 125 | - A place holder for future extensions. Drivers and applications | 130 | - A place holder for future extensions. Drivers and applications |
| 126 | must set the array to zero. | 131 | must set the array to zero. |
| 127 | 132 | ||
| @@ -260,7 +260,7 @@ call. · 259 unmodified lines | |||
| 260 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. | 260 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. |
| 261 | * - __s32 | 261 | * - __s32 |
| 262 | - ``default_value`` | 262 | - ``default_value`` |
| 263 | - The default value value of the control. See struct | 263 | - The default value of the control. See struct |
| 264 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. | 264 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. |
| 265 | 265 | ||
| 266 | 266 | ||
| @@ -51,25 +51,26 @@ To send a command applications must initialize all fields of a struct · 50 unmodified lines | |||
| 51 | ``VIDIOC_ENCODER_CMD`` or ``VIDIOC_TRY_ENCODER_CMD`` with a pointer to | 51 | ``VIDIOC_ENCODER_CMD`` or ``VIDIOC_TRY_ENCODER_CMD`` with a pointer to |
| 52 | this structure. | 52 | this structure. |
| 53 | 53 | ||
| 54 | The ``cmd`` field must contain the command code. The ``flags`` field is | 54 | The ``cmd`` field must contain the command code. Some commands use the |
| 55 | currently only used by the STOP command and contains one bit: If the | 55 | ``flags`` field for additional information. |
| 56 | ``V4L2_ENC_CMD_STOP_AT_GOP_END`` flag is set, encoding will continue | ||
| 57 | until the end of the current *Group Of Pictures*, otherwise it will stop | ||
| 58 | immediately. | ||
| 59 | 56 | ||
| 60 | A :ref:`read() <func-read>` or :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` | 57 | After a STOP command, :ref:`read() <func-read>` calls will read |
| 61 | call sends an implicit START command to the encoder if it has not been | ||
| 62 | started yet. After a STOP command, :ref:`read() <func-read>` calls will read | ||
| 63 | the remaining data buffered by the driver. When the buffer is empty, | 58 | the remaining data buffered by the driver. When the buffer is empty, |
| 64 | :ref:`read() <func-read>` will return zero and the next :ref:`read() <func-read>` | 59 | :ref:`read() <func-read>` will return zero and the next :ref:`read() <func-read>` |
| 65 | call will restart the encoder. | 60 | call will restart the encoder. |
| 66 | 61 | ||
| 62 | A :ref:`read() <func-read>` or :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` | ||
| 63 | call sends an implicit START command to the encoder if it has not been | ||
| 64 | started yet. Applies to both queues of mem2mem encoders. | ||
| 65 | |||
| 67 | A :ref:`close() <func-close>` or :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` | 66 | A :ref:`close() <func-close>` or :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` |
| 68 | call of a streaming file descriptor sends an implicit immediate STOP to | 67 | call of a streaming file descriptor sends an implicit immediate STOP to |
| 69 | the encoder, and all buffered data is discarded. | 68 | the encoder, and all buffered data is discarded. Applies to both queues of |
| 69 | mem2mem encoders. | ||
| 70 | 70 | ||
| 71 | These ioctls are optional, not all drivers may support them. They were | 71 | These ioctls are optional, not all drivers may support them. They were |
| 72 | introduced in Linux 2.6.21. | 72 | introduced in Linux 2.6.21. They are, however, mandatory for stateful mem2mem |
| 73 | encoders (as further documented in :ref:`encoder`). | ||
| 73 | 74 | ||
| 74 | 75 | ||
| 75 | .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| | 76 | .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| |
| @@ -109,21 +110,24 @@ introduced in Linux 2.6.21. · 33 unmodified lines | |||
| 109 | - 0 | 110 | - 0 |
| 110 | - Start the encoder. When the encoder is already running or paused, | 111 | - Start the encoder. When the encoder is already running or paused, |
| 111 | this command does nothing. No flags are defined for this command. | 112 | this command does nothing. No flags are defined for this command. |
| 113 | |||
| 114 | For a device implementing the :ref:`encoder`, once the drain sequence | ||
| 115 | is initiated with the ``V4L2_ENC_CMD_STOP`` command, it must be driven | ||
| 116 | to completion before this command can be invoked. Any attempt to | ||
| 117 | invoke the command while the drain sequence is in progress will trigger | ||
| 118 | an ``EBUSY`` error code. See :ref:`encoder` for more details. | ||
| 112 | * - ``V4L2_ENC_CMD_STOP`` | 119 | * - ``V4L2_ENC_CMD_STOP`` |
| 113 | - 1 | 120 | - 1 |
| 114 | - Stop the encoder. When the ``V4L2_ENC_CMD_STOP_AT_GOP_END`` flag | 121 | - Stop the encoder. When the ``V4L2_ENC_CMD_STOP_AT_GOP_END`` flag |
| 115 | is set, encoding will continue until the end of the current *Group | 122 | is set, encoding will continue until the end of the current *Group |
| 116 | Of Pictures*, otherwise encoding will stop immediately. When the | 123 | Of Pictures*, otherwise encoding will stop immediately. When the |
| 117 | encoder is already stopped, this command does nothing. mem2mem | 124 | encoder is already stopped, this command does nothing. |
| 118 | encoders will send a ``V4L2_EVENT_EOS`` event when the last frame | 125 | |
| 119 | has been encoded and all frames are ready to be dequeued and will | 126 | For a device implementing the :ref:`encoder`, the command will initiate |
| 120 | set the ``V4L2_BUF_FLAG_LAST`` buffer flag on the last buffer of | 127 | the drain sequence as documented in :ref:`encoder`. No flags or other |
| 121 | the capture queue to indicate there will be no new buffers | 128 | arguments are accepted in this case. Any attempt to invoke the command |
| 122 | produced to dequeue. This buffer may be empty, indicated by the | 129 | again before the sequence completes will trigger an ``EBUSY`` error |
| 123 | driver setting the ``bytesused`` field to 0. Once the | 130 | code. |
| 124 | ``V4L2_BUF_FLAG_LAST`` flag was set, the | ||
| 125 | :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl will not block anymore, | ||
| 126 | but return an ``EPIPE`` error code. | ||
| 127 | * - ``V4L2_ENC_CMD_PAUSE`` | 131 | * - ``V4L2_ENC_CMD_PAUSE`` |
| 128 | - 2 | 132 | - 2 |
| 129 | - Pause the encoder. When the encoder has not been started yet, the | 133 | - Pause the encoder. When the encoder has not been started yet, the |
| @@ -152,6 +156,8 @@ introduced in Linux 2.6.21. · 22 unmodified lines | |||
| 152 | - Stop encoding at the end of the current *Group Of Pictures*, | 156 | - Stop encoding at the end of the current *Group Of Pictures*, |
| 153 | rather than immediately. | 157 | rather than immediately. |
| 154 | 158 | ||
| 159 | Does not apply to :ref:`encoder`. | ||
| 160 | |||
| 155 | 161 | ||
| 156 | Return Value | 162 | Return Value |
| 157 | ============ | 163 | ============ |
| @@ -160,6 +166,11 @@ On success 0 is returned, on error -1 and the ``errno`` variable is set · 2 unmodified lines | |||
| 160 | appropriately. The generic error codes are described at the | 166 | appropriately. The generic error codes are described at the |
| 161 | :ref:`Generic Error Codes <gen-errors>` chapter. | 167 | :ref:`Generic Error Codes <gen-errors>` chapter. |
| 162 | 168 | ||
| 169 | EBUSY | ||
| 170 | A drain sequence of a device implementing the :ref:`encoder` is still in | ||
| 171 | progress. It is not allowed to issue another encoder command until it | ||
| 172 | completes. | ||
| 173 | |||
| 163 | EINVAL | 174 | EINVAL |
| 164 | The ``cmd`` field is invalid. | 175 | The ``cmd`` field is invalid. |
| 165 | 176 | ||
| @@ -167,17 +167,37 @@ the ``mbus_code`` field is handled differently: · 166 unmodified lines | |||
| 167 | - The hardware decoder for this compressed bytestream format (aka coded | 167 | - The hardware decoder for this compressed bytestream format (aka coded |
| 168 | format) is capable of parsing a continuous bytestream. Applications do | 168 | format) is capable of parsing a continuous bytestream. Applications do |
| 169 | not need to parse the bytestream themselves to find the boundaries | 169 | not need to parse the bytestream themselves to find the boundaries |
| 170 | between frames/fields. This flag can only be used in combination with | 170 | between frames/fields. |
| 171 | the ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to compressed | 171 | |
| 172 | This flag can only be used in combination with the | ||
| 173 | ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to compressed | ||
| 172 | formats only. This flag is valid for stateful decoders only. | 174 | formats only. This flag is valid for stateful decoders only. |
| 173 | * - ``V4L2_FMT_FLAG_DYN_RESOLUTION`` | 175 | * - ``V4L2_FMT_FLAG_DYN_RESOLUTION`` |
| 174 | - 0x0008 | 176 | - 0x0008 |
| 175 | - Dynamic resolution switching is supported by the device for this | 177 | - Dynamic resolution switching is supported by the device for this |
| 176 | compressed bytestream format (aka coded format). It will notify the user | 178 | compressed bytestream format (aka coded format). It will notify the user |
| 177 | via the event ``V4L2_EVENT_SOURCE_CHANGE`` when changes in the video | 179 | via the event ``V4L2_EVENT_SOURCE_CHANGE`` when changes in the video |
| 178 | parameters are detected. This flag can only be used in combination | 180 | parameters are detected. |
| 179 | with the ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to | 181 | |
| 180 | compressed formats only. It is also only applies to stateful codecs. | 182 | This flag can only be used in combination with the |
| 183 | ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to | ||
| 184 | compressed formats only. This flag is valid for stateful codecs only. | ||
| 185 | * - ``V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL`` | ||
| 186 | - 0x0010 | ||
| 187 | - The hardware encoder supports setting the ``CAPTURE`` coded frame | ||
| 188 | interval separately from the ``OUTPUT`` raw frame interval. | ||
| 189 | Setting the ``OUTPUT`` raw frame interval with :ref:`VIDIOC_S_PARM <VIDIOC_G_PARM>` | ||
| 190 | also sets the ``CAPTURE`` coded frame interval to the same value. | ||
| 191 | If this flag is set, then the ``CAPTURE`` coded frame interval can be | ||
| 192 | set to a different value afterwards. This is typically used for | ||
| 193 | offline encoding where the ``OUTPUT`` raw frame interval is used as | ||
| 194 | a hint for reserving hardware encoder resources and the ``CAPTURE`` coded | ||
| 195 | frame interval is the actual frame rate embedded in the encoded video | ||
| 196 | stream. | ||
| 197 | |||
| 198 | This flag can only be used in combination with the | ||
| 199 | ``V4L2_FMT_FLAG_COMPRESSED`` flag, since this applies to | ||
| 200 | compressed formats only. This flag is valid for stateful encoders only. | ||
| 181 | 201 | ||
| 182 | 202 | ||
| 183 | Return Value | 203 | Return Value |
| @@ -42,12 +42,13 @@ Arguments · 41 unmodified lines | |||
| 42 | Description | 42 | Description |
| 43 | =========== | 43 | =========== |
| 44 | 44 | ||
| 45 | The current video standard determines a nominal number of frames per | 45 | Applications can request a different frame interval. The capture or |
| 46 | second. If less than this number of frames is to be captured or output, | 46 | output device will be reconfigured to support the requested frame |
| 47 | applications can request frame skipping or duplicating on the driver | 47 | interval if possible. Optionally drivers may choose to skip or |
| 48 | side. This is especially useful when using the :ref:`read() <func-read>` or | 48 | repeat frames to achieve the requested frame interval. |
| 49 | :ref:`write() <func-write>`, which are not augmented by timestamps or sequence | 49 | |
| 50 | counters, and to avoid unnecessary data copying. | 50 | For stateful encoders (see :ref:`encoder`) this represents the |
| 51 | frame interval that is typically embedded in the encoded video stream. | ||
| 51 | 52 | ||
| 52 | Changing the frame interval shall never change the format. Changing the | 53 | Changing the frame interval shall never change the format. Changing the |
| 53 | format, on the other hand, may change the frame interval. | 54 | format, on the other hand, may change the frame interval. |
| @@ -57,7 +58,8 @@ internally by a driver in read/write mode. For implications see the · 3 unmodified lines | |||
| 57 | section discussing the :ref:`read() <func-read>` function. | 58 | section discussing the :ref:`read() <func-read>` function. |
| 58 | 59 | ||
| 59 | To get and set the streaming parameters applications call the | 60 | To get and set the streaming parameters applications call the |
| 60 | :ref:`VIDIOC_G_PARM <VIDIOC_G_PARM>` and :ref:`VIDIOC_S_PARM <VIDIOC_G_PARM>` ioctl, respectively. They take a | 61 | :ref:`VIDIOC_G_PARM <VIDIOC_G_PARM>` and |
| 62 | :ref:`VIDIOC_S_PARM <VIDIOC_G_PARM>` ioctl, respectively. They take a | ||
| 61 | pointer to a struct :c:type:`v4l2_streamparm` which contains a | 63 | pointer to a struct :c:type:`v4l2_streamparm` which contains a |
| 62 | union holding separate parameters for input and output devices. | 64 | union holding separate parameters for input and output devices. |
| 63 | 65 | ||
| @@ -113,14 +115,21 @@ union holding separate parameters for input and output devices. · 49 unmodified lines | |||
| 113 | * - struct :c:type:`v4l2_fract` | 115 | * - struct :c:type:`v4l2_fract` |
| 114 | - ``timeperframe`` | 116 | - ``timeperframe`` |
| 115 | - This is the desired period between successive frames captured by | 117 | - This is the desired period between successive frames captured by |
| 116 | the driver, in seconds. The field is intended to skip frames on | 118 | the driver, in seconds. |
| 117 | the driver side, saving I/O bandwidth. | 119 | * - :cspan:`2` |
| 120 | |||
| 121 | This will configure the speed at which the video source (e.g. a sensor) | ||
| 122 | generates video frames. If the speed is fixed, then the driver may | ||
| 123 | choose to skip or repeat frames in order to achieve the requested | ||
| 124 | frame rate. | ||
| 125 | |||
| 126 | For stateful encoders (see :ref:`encoder`) this represents the | ||
| 127 | frame interval that is typically embedded in the encoded video stream. | ||
| 118 | 128 | ||
| 119 | Applications store here the desired frame period, drivers return | 129 | Applications store here the desired frame period, drivers return |
| 120 | the actual frame period, which must be greater or equal to the | 130 | the actual frame period. |
| 121 | nominal frame period determined by the current video standard | 131 | |
| 122 | (struct :c:type:`v4l2_standard` ``frameperiod`` | 132 | Changing the video standard (also implicitly by switching |
| 123 | field). Changing the video standard (also implicitly by switching | ||
| 124 | the video input) may reset this parameter to the nominal frame | 133 | the video input) may reset this parameter to the nominal frame |
| 125 | period. To reset manually applications can just set this field to | 134 | period. To reset manually applications can just set this field to |
| 126 | zero. | 135 | zero. |
| @@ -173,11 +182,15 @@ union holding separate parameters for input and output devices. · 46 unmodified lines | |||
| 173 | :ref:`write() <func-write>` mode (in streaming mode timestamps | 182 | :ref:`write() <func-write>` mode (in streaming mode timestamps |
| 174 | can be used to throttle the output), saving I/O bandwidth. | 183 | can be used to throttle the output), saving I/O bandwidth. |
| 175 | 184 | ||
| 185 | For stateful encoders (see :ref:`encoder`) this represents the | ||
| 186 | frame interval that is typically embedded in the encoded video stream | ||
| 187 | and it provides a hint to the encoder of the speed at which raw | ||
| 188 | frames are queued up to the encoder. | ||
| 189 | |||
| 176 | Applications store here the desired frame period, drivers return | 190 | Applications store here the desired frame period, drivers return |
| 177 | the actual frame period, which must be greater or equal to the | 191 | the actual frame period. |
| 178 | nominal frame period determined by the current video standard | 192 | |
| 179 | (struct :c:type:`v4l2_standard` ``frameperiod`` | 193 | Changing the video standard (also implicitly by switching |
| 180 | field). Changing the video standard (also implicitly by switching | ||
| 181 | the video output) may reset this parameter to the nominal frame | 194 | the video output) may reset this parameter to the nominal frame |
| 182 | period. To reset manually applications can just set this field to | 195 | period. To reset manually applications can just set this field to |
| 183 | zero. | 196 | zero. |
| @@ -216,8 +229,8 @@ union holding separate parameters for input and output devices. · 32 unmodified lines | |||
| 216 | 229 | ||
| 217 | * - ``V4L2_CAP_TIMEPERFRAME`` | 230 | * - ``V4L2_CAP_TIMEPERFRAME`` |
| 218 | - 0x1000 | 231 | - 0x1000 |
| 219 | - The frame skipping/repeating controlled by the ``timeperframe`` | 232 | - The frame period can be modified by setting the ``timeperframe`` |
| 220 | field is supported. | 233 | field. |
| 221 | 234 | ||
| 222 | 235 | ||
| 223 | 236 | ||
| @@ -168,11 +168,11 @@ specification the ioctl returns an ``EINVAL`` error code. · 167 unmodified lines | |||
| 168 | - The device supports the :ref:`multi-planar API <planar-apis>` | 168 | - The device supports the :ref:`multi-planar API <planar-apis>` |
| 169 | through the :ref:`Video Output <output>` interface. | 169 | through the :ref:`Video Output <output>` interface. |
| 170 | * - ``V4L2_CAP_VIDEO_M2M`` | 170 | * - ``V4L2_CAP_VIDEO_M2M`` |
| 171 | - 0x00004000 | 171 | - 0x00008000 |
| 172 | - The device supports the single-planar API through the Video | 172 | - The device supports the single-planar API through the Video |
| 173 | Memory-To-Memory interface. | 173 | Memory-To-Memory interface. |
| 174 | * - ``V4L2_CAP_VIDEO_M2M_MPLANE`` | 174 | * - ``V4L2_CAP_VIDEO_M2M_MPLANE`` |
| 175 | - 0x00008000 | 175 | - 0x00004000 |
| 176 | - The device supports the :ref:`multi-planar API <planar-apis>` | 176 | - The device supports the :ref:`multi-planar API <planar-apis>` |
| 177 | through the Video Memory-To-Memory interface. | 177 | through the Video Memory-To-Memory interface. |
| 178 | * - ``V4L2_CAP_VIDEO_OVERLAY`` | 178 | * - ``V4L2_CAP_VIDEO_OVERLAY`` |
| @@ -112,10 +112,17 @@ aborting or finishing any DMA in progress, an implicit · 111 unmodified lines | |||
| 112 | ``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will | 112 | ``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will |
| 113 | free any previously allocated buffers, so this is typically something | 113 | free any previously allocated buffers, so this is typically something |
| 114 | that will be done at the start of the application. | 114 | that will be done at the start of the application. |
| 115 | * - union { | ||
| 116 | - (anonymous) | ||
| 117 | * - __u32 | ||
| 118 | - ``flags`` | ||
| 119 | - Specifies additional buffer management attributes. | ||
| 120 | See :ref:`memory-flags`. | ||
| 115 | * - __u32 | 121 | * - __u32 |
| 116 | - ``reserved``\ [1] | 122 | - ``reserved``\ [1] |
| 117 | - A place holder for future extensions. Drivers and applications | 123 | - Kept for backwards compatibility. Use ``flags`` instead. |
| 118 | must set the array to zero. | 124 | * - } |
| 125 | - | ||
| 119 | 126 | ||
| 120 | .. tabularcolumns:: |p{6.1cm}|p{2.2cm}|p{8.7cm}| | 127 | .. tabularcolumns:: |p{6.1cm}|p{2.2cm}|p{8.7cm}| |
| 121 | 128 | ||
| @@ -126,6 +133,7 @@ aborting or finishing any DMA in progress, an implicit · 4 unmodified lines | |||
| 126 | .. _V4L2-BUF-CAP-SUPPORTS-REQUESTS: | 133 | .. _V4L2-BUF-CAP-SUPPORTS-REQUESTS: |
| 127 | .. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS: | 134 | .. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS: |
| 128 | .. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF: | 135 | .. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF: |
| 136 | .. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS: | ||
| 129 | 137 | ||
| 130 | .. cssclass:: longtable | 138 | .. cssclass:: longtable |
| 131 | 139 | ||
| @@ -156,6 +164,15 @@ aborting or finishing any DMA in progress, an implicit · 24 unmodified lines | |||
| 156 | - Only valid for stateless decoders. If set, then userspace can set the | 164 | - Only valid for stateless decoders. If set, then userspace can set the |
| 157 | ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag to hold off on returning the | 165 | ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag to hold off on returning the |
| 158 | capture buffer until the OUTPUT timestamp changes. | 166 | capture buffer until the OUTPUT timestamp changes. |
| 167 | * - ``V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS`` | ||
| 168 | - 0x00000040 | ||
| 169 | - This capability is set by the driver to indicate that the queue supports | ||
| 170 | cache and memory management hints. However, it's only valid when the | ||
| 171 | queue is used for :ref:`memory mapping <mmap>` streaming I/O. See | ||
| 172 | :ref:`V4L2_FLAG_MEMORY_NON_CONSISTENT <V4L2-FLAG-MEMORY-NON-CONSISTENT>`, | ||
| 173 | :ref:`V4L2_BUF_FLAG_NO_CACHE_INVALIDATE <V4L2-BUF-FLAG-NO-CACHE-INVALIDATE>` and | ||
| 174 | :ref:`V4L2_BUF_FLAG_NO_CACHE_CLEAN <V4L2-BUF-FLAG-NO-CACHE-CLEAN>`. | ||
| 175 | |||
| 159 | 176 | ||
| 160 | Return Value | 177 | Return Value |
| 161 | ============ | 178 | ============ |
| @@ -187,6 +187,7 @@ replace define V4L2_FMT_FLAG_COMPRESSED fmtdesc-flags · 186 unmodified lines | |||
| 187 | replace define V4L2_FMT_FLAG_EMULATED fmtdesc-flags | 187 | replace define V4L2_FMT_FLAG_EMULATED fmtdesc-flags |
| 188 | replace define V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM fmtdesc-flags | 188 | replace define V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM fmtdesc-flags |
| 189 | replace define V4L2_FMT_FLAG_DYN_RESOLUTION fmtdesc-flags | 189 | replace define V4L2_FMT_FLAG_DYN_RESOLUTION fmtdesc-flags |
| 190 | replace define V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL fmtdesc-flags | ||
| 190 | 191 | ||
| 191 | # V4L2 timecode types | 192 | # V4L2 timecode types |
| 192 | replace define V4L2_TC_TYPE_24FPS timecode-type | 193 | replace define V4L2_TC_TYPE_24FPS timecode-type |
| @@ -4141,6 +4141,14 @@ F: drivers/power/supply/cros_usbpd-charger.c · 4140 unmodified lines | |||
| 4141 | N: cros_ec | 4141 | N: cros_ec |
| 4142 | N: cros-ec | 4142 | N: cros-ec |
| 4143 | 4143 | ||
| 4144 | CHRONTEL CH7322 CEC DRIVER | ||
| 4145 | M: Jeff Chase <jnchase@google.com> | ||
| 4146 | L: linux-media@vger.kernel.org | ||
| 4147 | S: Maintained | ||
| 4148 | T: git git://linuxtv.org/media_tree.git | ||
| 4149 | F: Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml | ||
| 4150 | F: drivers/media/cec/i2c/ch7322.c | ||
| 4151 | |||
| 4144 | CIRRUS LOGIC AUDIO CODEC DRIVERS | 4152 | CIRRUS LOGIC AUDIO CODEC DRIVERS |
| 4145 | M: James Schulman <james.schulman@cirrus.com> | 4153 | M: James Schulman <james.schulman@cirrus.com> |
| 4146 | M: David Rhodes <david.rhodes@cirrus.com> | 4154 | M: David Rhodes <david.rhodes@cirrus.com> |
| @@ -5267,6 +5275,14 @@ T: git git://linuxtv.org/media_tree.git · 1120 unmodified lines | |||
| 5267 | F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt | 5275 | F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt |
| 5268 | F: drivers/media/i2c/dw9714.c | 5276 | F: drivers/media/i2c/dw9714.c |
| 5269 | 5277 | ||
| 5278 | DONGWOON DW9768 LENS VOICE COIL DRIVER | ||
| 5279 | M: Dongchun Zhu <dongchun.zhu@mediatek.com> | ||
| 5280 | L: linux-media@vger.kernel.org | ||
| 5281 | S: Maintained | ||
| 5282 | T: git git://linuxtv.org/media_tree.git | ||
| 5283 | F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml | ||
| 5284 | F: drivers/media/i2c/dw9768.c | ||
| 5285 | |||
| 5270 | DONGWOON DW9807 LENS VOICE COIL DRIVER | 5286 | DONGWOON DW9807 LENS VOICE COIL DRIVER |
| 5271 | M: Sakari Ailus <sakari.ailus@linux.intel.com> | 5287 | M: Sakari Ailus <sakari.ailus@linux.intel.com> |
| 5272 | L: linux-media@vger.kernel.org | 5288 | L: linux-media@vger.kernel.org |
| @@ -10507,6 +10523,16 @@ F: Documentation/hwmon/max6697.rst · 5234 unmodified lines | |||
| 10507 | F: drivers/hwmon/max6697.c | 10523 | F: drivers/hwmon/max6697.c |
| 10508 | F: include/linux/platform_data/max6697.h | 10524 | F: include/linux/platform_data/max6697.h |
| 10509 | 10525 | ||
| 10526 | MAX9286 QUAD GMSL DESERIALIZER DRIVER | ||
| 10527 | M: Jacopo Mondi <jacopo+renesas@jmondi.org> | ||
| 10528 | M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> | ||
| 10529 | M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | ||
| 10530 | M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> | ||
| 10531 | L: linux-media@vger.kernel.org | ||
| 10532 | S: Maintained | ||
| 10533 | F: Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml | ||
| 10534 | F: drivers/media/i2c/max9286.c | ||
| 10535 | |||
| 10510 | MAX9860 MONO AUDIO VOICE CODEC DRIVER | 10536 | MAX9860 MONO AUDIO VOICE CODEC DRIVER |
| 10511 | M: Peter Rosin <peda@axentia.se> | 10537 | M: Peter Rosin <peda@axentia.se> |
| 10512 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 10538 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
| @@ -10785,7 +10811,7 @@ L: linux-media@vger.kernel.org · 272 unmodified lines | |||
| 10785 | L: linux-renesas-soc@vger.kernel.org | 10811 | L: linux-renesas-soc@vger.kernel.org |
| 10786 | S: Supported | 10812 | S: Supported |
| 10787 | T: git git://linuxtv.org/media_tree.git | 10813 | T: git git://linuxtv.org/media_tree.git |
| 10788 | F: Documentation/devicetree/bindings/media/renesas,fcp.txt | 10814 | F: Documentation/devicetree/bindings/media/renesas,fcp.yaml |
| 10789 | F: drivers/media/platform/rcar-fcp.c | 10815 | F: drivers/media/platform/rcar-fcp.c |
| 10790 | F: include/media/rcar-fcp.h | 10816 | F: include/media/rcar-fcp.h |
| 10791 | 10817 | ||
| @@ -10795,7 +10821,7 @@ L: linux-media@vger.kernel.org · 3 unmodified lines | |||
| 10795 | L: linux-renesas-soc@vger.kernel.org | 10821 | L: linux-renesas-soc@vger.kernel.org |
| 10796 | S: Supported | 10822 | S: Supported |
| 10797 | T: git git://linuxtv.org/media_tree.git | 10823 | T: git git://linuxtv.org/media_tree.git |
| 10798 | F: Documentation/devicetree/bindings/media/renesas,fdp1.txt | 10824 | F: Documentation/devicetree/bindings/media/renesas,fdp1.yaml |
| 10799 | F: drivers/media/platform/rcar_fdp1.c | 10825 | F: drivers/media/platform/rcar_fdp1.c |
| 10800 | 10826 | ||
| 10801 | MEDIA DRIVERS FOR RENESAS - VIN | 10827 | MEDIA DRIVERS FOR RENESAS - VIN |
| @@ -10815,7 +10841,7 @@ L: linux-media@vger.kernel.org · 13 unmodified lines | |||
| 10815 | L: linux-renesas-soc@vger.kernel.org | 10841 | L: linux-renesas-soc@vger.kernel.org |
| 10816 | S: Supported | 10842 | S: Supported |
| 10817 | T: git git://linuxtv.org/media_tree.git | 10843 | T: git git://linuxtv.org/media_tree.git |
| 10818 | F: Documentation/devicetree/bindings/media/renesas,vsp1.txt | 10844 | F: Documentation/devicetree/bindings/media/renesas,vsp1.yaml |
| 10819 | F: drivers/media/platform/vsp1/ | 10845 | F: drivers/media/platform/vsp1/ |
| 10820 | 10846 | ||
| 10821 | MEDIA DRIVERS FOR ST STV0910 DEMODULATOR ICs | 10847 | MEDIA DRIVERS FOR ST STV0910 DEMODULATOR ICs |
| @@ -14483,6 +14509,19 @@ L: linux-wireless@vger.kernel.org · 3661 unmodified lines | |||
| 14483 | S: Orphan | 14509 | S: Orphan |
| 14484 | F: drivers/net/wireless/ray* | 14510 | F: drivers/net/wireless/ray* |
| 14485 | 14511 | ||
| 14512 | RC-CORE / LIRC FRAMEWORK | ||
| 14513 | M: Sean Young <sean@mess.org> | ||
| 14514 | L: linux-media@vger.kernel.org | ||
| 14515 | S: Maintained | ||
| 14516 | W: http://linuxtv.org | ||
| 14517 | T: git git://linuxtv.org/media_tree.git | ||
| 14518 | F: Documentation/driver-api/media/rc-core.rst | ||
| 14519 | F: Documentation/userspace-api/media/rc/ | ||
| 14520 | F: drivers/media/rc/ | ||
| 14521 | F: include/media/rc-map.h | ||
| 14522 | F: include/media/rc-core.h | ||
| 14523 | F: include/uapi/linux/lirc.h | ||
| 14524 | |||
| 14486 | RCMM REMOTE CONTROLS DECODER | 14525 | RCMM REMOTE CONTROLS DECODER |
| 14487 | M: Patrick Lerda <patrick9876@free.fr> | 14526 | M: Patrick Lerda <patrick9876@free.fr> |
| 14488 | S: Maintained | 14527 | S: Maintained |
| @@ -14499,6 +14538,18 @@ S: Supported · 10 unmodified lines | |||
| 14499 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev | 14538 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git dev |
| 14500 | F: tools/testing/selftests/rcutorture | 14539 | F: tools/testing/selftests/rcutorture |
| 14501 | 14540 | ||
| 14541 | RDACM20 Camera Sensor | ||
| 14542 | M: Jacopo Mondi <jacopo+renesas@jmondi.org> | ||
| 14543 | M: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> | ||
| 14544 | M: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | ||
| 14545 | M: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> | ||
| 14546 | L: linux-media@vger.kernel.org | ||
| 14547 | S: Maintained | ||
| 14548 | F: Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml | ||
| 14549 | F: drivers/media/i2c/rdacm20.c | ||
| 14550 | F: drivers/media/i2c/max9271.c | ||
| 14551 | F: drivers/media/i2c/max9271.h | ||
| 14552 | |||
| 14502 | RDC R-321X SoC | 14553 | RDC R-321X SoC |
| 14503 | M: Florian Fainelli <florian@openwrt.org> | 14554 | M: Florian Fainelli <florian@openwrt.org> |
| 14504 | S: Maintained | 14555 | S: Maintained |
| @@ -15887,13 +15938,6 @@ L: netdev@vger.kernel.org · 1382 unmodified lines | |||
| 15887 | S: Maintained | 15938 | S: Maintained |
| 15888 | F: drivers/net/ethernet/smsc/smsc9420.* | 15939 | F: drivers/net/ethernet/smsc/smsc9420.* |
| 15889 | 15940 | ||
| 15890 | SOC-CAMERA V4L2 SUBSYSTEM | ||
| 15891 | L: linux-media@vger.kernel.org | ||
| 15892 | S: Orphan | ||
| 15893 | T: git git://linuxtv.org/media_tree.git | ||
| 15894 | F: drivers/staging/media/soc_camera/ | ||
| 15895 | F: include/media/soc_camera.h | ||
| 15896 | |||
| 15897 | SOCIONEXT (SNI) AVE NETWORK DRIVER | 15941 | SOCIONEXT (SNI) AVE NETWORK DRIVER |
| 15898 | M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> | 15942 | M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> |
| 15899 | L: netdev@vger.kernel.org | 15943 | L: netdev@vger.kernel.org |
| @@ -236,8 +236,6 @@ CONFIG_MEDIA_TUNER_CUSTOMISE=y · 235 unmodified lines | |||
| 236 | # CONFIG_MEDIA_TUNER_MXL5007T is not set | 236 | # CONFIG_MEDIA_TUNER_MXL5007T is not set |
| 237 | # CONFIG_MEDIA_TUNER_MC44S803 is not set | 237 | # CONFIG_MEDIA_TUNER_MC44S803 is not set |
| 238 | # CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set | 238 | # CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set |
| 239 | CONFIG_SOC_CAMERA=y | ||
| 240 | CONFIG_SOC_CAMERA_MT9M111=y | ||
| 241 | CONFIG_VIDEO_PXA27x=y | 239 | CONFIG_VIDEO_PXA27x=y |
| 242 | # CONFIG_V4L_USB_DRIVERS is not set | 240 | # CONFIG_V4L_USB_DRIVERS is not set |
| 243 | CONFIG_RADIO_TEA5764=y | 241 | CONFIG_RADIO_TEA5764=y |
| @@ -217,8 +217,6 @@ CONFIG_MEDIA_TUNER_CUSTOMISE=y · 216 unmodified lines | |||
| 217 | # CONFIG_MEDIA_TUNER_MXL5007T is not set | 217 | # CONFIG_MEDIA_TUNER_MXL5007T is not set |
| 218 | # CONFIG_MEDIA_TUNER_MC44S803 is not set | 218 | # CONFIG_MEDIA_TUNER_MC44S803 is not set |
| 219 | # CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set | 219 | # CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set |
| 220 | CONFIG_SOC_CAMERA=y | ||
| 221 | CONFIG_SOC_CAMERA_MT9M111=y | ||
| 222 | CONFIG_VIDEO_PXA27x=y | 220 | CONFIG_VIDEO_PXA27x=y |
| 223 | # CONFIG_V4L_USB_DRIVERS is not set | 221 | # CONFIG_V4L_USB_DRIVERS is not set |
| 224 | # CONFIG_RADIO_ADAPTERS is not set | 222 | # CONFIG_RADIO_ADAPTERS is not set |
| @@ -110,7 +110,6 @@ CONFIG_REGULATOR_MC13892=y · 109 unmodified lines | |||
| 110 | CONFIG_MEDIA_SUPPORT=y | 110 | CONFIG_MEDIA_SUPPORT=y |
| 111 | CONFIG_MEDIA_CAMERA_SUPPORT=y | 111 | CONFIG_MEDIA_CAMERA_SUPPORT=y |
| 112 | CONFIG_V4L_PLATFORM_DRIVERS=y | 112 | CONFIG_V4L_PLATFORM_DRIVERS=y |
| 113 | CONFIG_SOC_CAMERA=y | ||
| 114 | CONFIG_V4L_MEM2MEM_DRIVERS=y | 113 | CONFIG_V4L_MEM2MEM_DRIVERS=y |
| 115 | CONFIG_VIDEO_CODA=y | 114 | CONFIG_VIDEO_CODA=y |
| 116 | CONFIG_FB=y | 115 | CONFIG_FB=y |
| @@ -272,7 +272,6 @@ CONFIG_MEDIA_USB_SUPPORT=y · 271 unmodified lines | |||
| 272 | CONFIG_USB_VIDEO_CLASS=m | 272 | CONFIG_USB_VIDEO_CLASS=m |
| 273 | CONFIG_V4L_PLATFORM_DRIVERS=y | 273 | CONFIG_V4L_PLATFORM_DRIVERS=y |
| 274 | CONFIG_VIDEO_MUX=y | 274 | CONFIG_VIDEO_MUX=y |
| 275 | CONFIG_SOC_CAMERA=y | ||
| 276 | CONFIG_V4L_MEM2MEM_DRIVERS=y | 275 | CONFIG_V4L_MEM2MEM_DRIVERS=y |
| 277 | CONFIG_VIDEO_CODA=m | 276 | CONFIG_VIDEO_CODA=m |
| 278 | CONFIG_VIDEO_IMX_PXP=y | 277 | CONFIG_VIDEO_IMX_PXP=y |
| @@ -447,11 +447,8 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y · 446 unmodified lines | |||
| 447 | CONFIG_MEDIA_USB_SUPPORT=y | 447 | CONFIG_MEDIA_USB_SUPPORT=y |
| 448 | CONFIG_USB_VIDEO_CLASS=m | 448 | CONFIG_USB_VIDEO_CLASS=m |
| 449 | CONFIG_V4L_PLATFORM_DRIVERS=y | 449 | CONFIG_V4L_PLATFORM_DRIVERS=y |
| 450 | CONFIG_SOC_CAMERA=m | ||
| 451 | CONFIG_SOC_CAMERA_PLATFORM=m | ||
| 452 | CONFIG_VIDEO_PXA27x=m | 450 | CONFIG_VIDEO_PXA27x=m |
| 453 | CONFIG_V4L_MEM2MEM_DRIVERS=y | 451 | CONFIG_V4L_MEM2MEM_DRIVERS=y |
| 454 | CONFIG_SOC_CAMERA_MT9M111=m | ||
| 455 | CONFIG_DRM=m | 452 | CONFIG_DRM=m |
| 456 | CONFIG_FIRMWARE_EDID=y | 453 | CONFIG_FIRMWARE_EDID=y |
| 457 | CONFIG_FB_TILEBLITTING=y | 454 | CONFIG_FB_TILEBLITTING=y |
| @@ -155,9 +155,7 @@ CONFIG_REGULATOR_PWM=m · 154 unmodified lines | |||
| 155 | CONFIG_MEDIA_SUPPORT=y | 155 | CONFIG_MEDIA_SUPPORT=y |
| 156 | CONFIG_MEDIA_CAMERA_SUPPORT=y | 156 | CONFIG_MEDIA_CAMERA_SUPPORT=y |
| 157 | CONFIG_V4L_PLATFORM_DRIVERS=y | 157 | CONFIG_V4L_PLATFORM_DRIVERS=y |
| 158 | CONFIG_SOC_CAMERA=y | ||
| 159 | CONFIG_VIDEO_ATMEL_ISI=y | 158 | CONFIG_VIDEO_ATMEL_ISI=y |
| 160 | CONFIG_SOC_CAMERA_OV2640=m | ||
| 161 | CONFIG_DRM=y | 159 | CONFIG_DRM=y |
| 162 | CONFIG_DRM_ATMEL_HLCDC=y | 160 | CONFIG_DRM_ATMEL_HLCDC=y |
| 163 | CONFIG_DRM_PANEL_SIMPLE=y | 161 | CONFIG_DRM_PANEL_SIMPLE=y |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
| 20 | #include <linux/leds.h> | 20 | #include <linux/leds.h> |
| 21 | #include <linux/platform_data/asoc-mx27vis.h> | 21 | #include <linux/platform_data/asoc-mx27vis.h> |
| 22 | #include <media/soc_camera.h> | ||
| 23 | #include <sound/tlv320aic32x4.h> | 22 | #include <sound/tlv320aic32x4.h> |
| 24 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
| 25 | #include <asm/mach/arch.h> | 24 | #include <asm/mach/arch.h> |
| @@ -191,34 +190,6 @@ static const struct gpio visstrim_m10_gpios[] __initconst = { · 165 unmodified lines | |||
| 191 | }; | 190 | }; |
| 192 | 191 | ||
| 193 | /* Camera */ | 192 | /* Camera */ |
| 194 | static int visstrim_camera_power(struct device *dev, int on) | ||
| 195 | { | ||
| 196 | gpio_set_value(TVP5150_PWDN, on); | ||
| 197 | |||
| 198 | return 0; | ||
| 199 | }; | ||
| 200 | |||
| 201 | static int visstrim_camera_reset(struct device *dev) | ||
| 202 | { | ||
| 203 | gpio_set_value(TVP5150_RSTN, 0); | ||
| 204 | ndelay(500); | ||
| 205 | gpio_set_value(TVP5150_RSTN, 1); | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | }; | ||
| 209 | |||
| 210 | static struct i2c_board_info visstrim_i2c_camera = { | ||
| 211 | I2C_BOARD_INFO("tvp5150", 0x5d), | ||
| 212 | }; | ||
| 213 | |||
| 214 | static struct soc_camera_link iclink_tvp5150 = { | ||
| 215 | .bus_id = 0, | ||
| 216 | .board_info = &visstrim_i2c_camera, | ||
| 217 | .i2c_adapter_id = 0, | ||
| 218 | .power = visstrim_camera_power, | ||
| 219 | .reset = visstrim_camera_reset, | ||
| 220 | }; | ||
| 221 | |||
| 222 | static struct mx2_camera_platform_data visstrim_camera = { | 193 | static struct mx2_camera_platform_data visstrim_camera = { |
| 223 | .flags = MX2_CAMERA_CCIR | MX2_CAMERA_CCIR_INTERLACE | | 194 | .flags = MX2_CAMERA_CCIR | MX2_CAMERA_CCIR_INTERLACE | |
| 224 | MX2_CAMERA_PCLK_SAMPLE_RISING, | 195 | MX2_CAMERA_PCLK_SAMPLE_RISING, |
| @@ -549,8 +520,6 @@ static void __init visstrim_m10_late_init(void) · 324 unmodified lines | |||
| 549 | 520 | ||
| 550 | imx_add_platform_device("mx27vis", 0, NULL, 0, &snd_mx27vis_pdata, | 521 | imx_add_platform_device("mx27vis", 0, NULL, 0, &snd_mx27vis_pdata, |
| 551 | sizeof(snd_mx27vis_pdata)); | 522 | sizeof(snd_mx27vis_pdata)); |
| 552 | platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0, | ||
| 553 | &iclink_tvp5150, sizeof(iclink_tvp5150)); | ||
| 554 | 523 | ||
| 555 | gpio_led_register_device(0, &visstrim_m10_led_data); | 524 | gpio_led_register_device(0, &visstrim_m10_led_data); |
| 556 | 525 | ||
| @@ -29,8 +29,6 @@ · 28 unmodified lines | |||
| 29 | #include <linux/io.h> | 29 | #include <linux/io.h> |
| 30 | #include <linux/platform_data/gpio-omap.h> | 30 | #include <linux/platform_data/gpio-omap.h> |
| 31 | 31 | ||
| 32 | #include <media/soc_camera.h> | ||
| 33 | |||
| 34 | #include <asm/serial.h> | 32 | #include <asm/serial.h> |
| 35 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
| 36 | #include <asm/mach/arch.h> | 34 | #include <asm/mach/arch.h> |
| @@ -40,7 +38,6 @@ · 3 unmodified lines | |||
| 40 | #include <mach/mux.h> | 38 | #include <mach/mux.h> |
| 41 | 39 | ||
| 42 | #include <mach/hardware.h> | 40 | #include <mach/hardware.h> |
| 43 | #include "camera.h" | ||
| 44 | #include <mach/usb.h> | 41 | #include <mach/usb.h> |
| 45 | 42 | ||
| 46 | #include "ams-delta-fiq.h" | 43 | #include "ams-delta-fiq.h" |
| @@ -459,12 +456,6 @@ static struct gpiod_lookup_table leds_gpio_table = { · 412 unmodified lines | |||
| 459 | }, | 456 | }, |
| 460 | }; | 457 | }; |
| 461 | 458 | ||
| 462 | static struct i2c_board_info ams_delta_camera_board_info[] = { | ||
| 463 | { | ||
| 464 | I2C_BOARD_INFO("ov6650", 0x60), | ||
| 465 | }, | ||
| 466 | }; | ||
| 467 | |||
| 468 | #ifdef CONFIG_LEDS_TRIGGERS | 459 | #ifdef CONFIG_LEDS_TRIGGERS |
| 469 | DEFINE_LED_TRIGGER(ams_delta_camera_led_trigger); | 460 | DEFINE_LED_TRIGGER(ams_delta_camera_led_trigger); |
| 470 | 461 | ||
| @@ -483,27 +474,6 @@ static int ams_delta_camera_power(struct device *dev, int power) · 12 unmodified lines | |||
| 483 | #define ams_delta_camera_power NULL | 474 | #define ams_delta_camera_power NULL |
| 484 | #endif | 475 | #endif |
| 485 | 476 | ||
| 486 | static struct soc_camera_link ams_delta_iclink = { | ||
| 487 | .bus_id = 0, /* OMAP1 SoC camera bus */ | ||
| 488 | .i2c_adapter_id = 1, | ||
| 489 | .board_info = &ams_delta_camera_board_info[0], | ||
| 490 | .module_name = "ov6650", | ||
| 491 | .power = ams_delta_camera_power, | ||
| 492 | }; | ||
| 493 | |||
| 494 | static struct platform_device ams_delta_camera_device = { | ||
| 495 | .name = "soc-camera-pdrv", | ||
| 496 | .id = 0, | ||
| 497 | .dev = { | ||
| 498 | .platform_data = &ams_delta_iclink, | ||
| 499 | }, | ||
| 500 | }; | ||
| 501 | |||
| 502 | static struct omap1_cam_platform_data ams_delta_camera_platform_data = { | ||
| 503 | .camexclk_khz = 12000, /* default 12MHz clock, no extra DPLL */ | ||
| 504 | .lclk_khz_max = 1334, /* results in 5fps CIF, 10fps QCIF */ | ||
| 505 | }; | ||
| 506 | |||
| 507 | static struct platform_device ams_delta_audio_device = { | 477 | static struct platform_device ams_delta_audio_device = { |
| 508 | .name = "ams-delta-audio", | 478 | .name = "ams-delta-audio", |
| 509 | .id = -1, | 479 | .id = -1, |
| @@ -598,7 +568,6 @@ static struct platform_device *ams_delta_devices[] __initdata = { · 88 unmodified lines | |||
| 598 | &latch1_gpio_device, | 568 | &latch1_gpio_device, |
| 599 | &latch2_gpio_device, | 569 | &latch2_gpio_device, |
| 600 | &ams_delta_kp_device, | 570 | &ams_delta_kp_device, |
| 601 | &ams_delta_camera_device, | ||
| 602 | &ams_delta_audio_device, | 571 | &ams_delta_audio_device, |
| 603 | &ams_delta_serio_device, | 572 | &ams_delta_serio_device, |
| 604 | &ams_delta_nand_device, | 573 | &ams_delta_nand_device, |
| @@ -750,7 +719,6 @@ static void __init ams_delta_init(void) · 145 unmodified lines | |||
| 750 | omap_register_i2c_bus(1, 100, NULL, 0); | 719 | omap_register_i2c_bus(1, 100, NULL, 0); |
| 751 | 720 | ||
| 752 | omap1_usb_init(&ams_delta_usb_config); | 721 | omap1_usb_init(&ams_delta_usb_config); |
| 753 | omap1_set_camera_info(&ams_delta_camera_platform_data); | ||
| 754 | #ifdef CONFIG_LEDS_TRIGGERS | 722 | #ifdef CONFIG_LEDS_TRIGGERS |
| 755 | led_trigger_register_simple("ams_delta_camera", | 723 | led_trigger_register_simple("ams_delta_camera", |
| 756 | &ams_delta_camera_led_trigger); | 724 | &ams_delta_camera_led_trigger); |
| @@ -1,14 +0,0 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef __ASM_ARCH_CAMERA_H_ | ||
| 3 | #define __ASM_ARCH_CAMERA_H_ | ||
| 4 | |||
| 5 | #include <linux/platform_data/media/omap1_camera.h> | ||
| 6 | |||
| 7 | void omap1_camera_init(void *); | ||
| 8 | |||
| 9 | static inline void omap1_set_camera_info(struct omap1_cam_platform_data *info) | ||
| 10 | { | ||
| 11 | omap1_camera_init(info); | ||
| 12 | } | ||
| 13 | |||
| 14 | #endif /* __ASM_ARCH_CAMERA_H_ */ | ||
| @@ -21,7 +21,6 @@ · 20 unmodified lines | |||
| 21 | #include <mach/mux.h> | 21 | #include <mach/mux.h> |
| 22 | 22 | ||
| 23 | #include <mach/omap7xx.h> | 23 | #include <mach/omap7xx.h> |
| 24 | #include "camera.h" | ||
| 25 | #include <mach/hardware.h> | 24 | #include <mach/hardware.h> |
| 26 | 25 | ||
| 27 | #include "common.h" | 26 | #include "common.h" |
| @@ -258,48 +257,6 @@ static inline void omap_init_spi100k(void) · 230 unmodified lines | |||
| 258 | } | 257 | } |
| 259 | #endif | 258 | #endif |
| 260 | 259 | ||
| 261 | |||
| 262 | #define OMAP1_CAMERA_BASE 0xfffb6800 | ||
| 263 | #define OMAP1_CAMERA_IOSIZE 0x1c | ||
| 264 | |||
| 265 | static struct resource omap1_camera_resources[] = { | ||
| 266 | [0] = { | ||
| 267 | .start = OMAP1_CAMERA_BASE, | ||
| 268 | .end = OMAP1_CAMERA_BASE + OMAP1_CAMERA_IOSIZE - 1, | ||
| 269 | .flags = IORESOURCE_MEM, | ||
| 270 | }, | ||
| 271 | [1] = { | ||
| 272 | .start = INT_CAMERA, | ||
| 273 | .flags = IORESOURCE_IRQ, | ||
| 274 | }, | ||
| 275 | }; | ||
| 276 | |||
| 277 | static u64 omap1_camera_dma_mask = DMA_BIT_MASK(32); | ||
| 278 | |||
| 279 | static struct platform_device omap1_camera_device = { | ||
| 280 | .name = "omap1-camera", | ||
| 281 | .id = 0, /* This is used to put cameras on this interface */ | ||
| 282 | .dev = { | ||
| 283 | .dma_mask = &omap1_camera_dma_mask, | ||
| 284 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
| 285 | }, | ||
| 286 | .num_resources = ARRAY_SIZE(omap1_camera_resources), | ||
| 287 | .resource = omap1_camera_resources, | ||
| 288 | }; | ||
| 289 | |||
| 290 | void __init omap1_camera_init(void *info) | ||
| 291 | { | ||
| 292 | struct platform_device *dev = &omap1_camera_device; | ||
| 293 | int ret; | ||
| 294 | |||
| 295 | dev->dev.platform_data = info; | ||
| 296 | |||
| 297 | ret = platform_device_register(dev); | ||
| 298 | if (ret) | ||
| 299 | dev_err(&dev->dev, "unable to register device: %d\n", ret); | ||
| 300 | } | ||
| 301 | |||
| 302 | |||
| 303 | /*-------------------------------------------------------------------------*/ | 260 | /*-------------------------------------------------------------------------*/ |
| 304 | 261 | ||
| 305 | static inline void omap_init_sti(void) {} | 262 | static inline void omap_init_sti(void) {} |
| @@ -47,8 +47,6 @@ · 46 unmodified lines | |||
| 47 | #include "pm.h" | 47 | #include "pm.h" |
| 48 | #include <linux/platform_data/media/camera-pxa.h> | 48 | #include <linux/platform_data/media/camera-pxa.h> |
| 49 | 49 | ||
| 50 | #include <media/soc_camera.h> | ||
| 51 | |||
| 52 | #include "generic.h" | 50 | #include "generic.h" |
| 53 | #include "devices.h" | 51 | #include "devices.h" |
| 54 | 52 | ||
| @@ -272,115 +270,6 @@ static int __init palmz72_pm_init(void) · 217 unmodified lines | |||
| 272 | device_initcall(palmz72_pm_init); | 270 | device_initcall(palmz72_pm_init); |
| 273 | #endif | 271 | #endif |
| 274 | 272 | ||
| 275 | /****************************************************************************** | ||
| 276 | * SoC Camera | ||
| 277 | ******************************************************************************/ | ||
| 278 | #if defined(CONFIG_SOC_CAMERA_OV9640) || \ | ||
| 279 | defined(CONFIG_SOC_CAMERA_OV9640_MODULE) | ||
| 280 | static struct pxacamera_platform_data palmz72_pxacamera_platform_data = { | ||
| 281 | .flags = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 | | ||
| 282 | PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN, | ||
| 283 | .mclk_10khz = 2600, | ||
| 284 | }; | ||
| 285 | |||
| 286 | /* Board I2C devices. */ | ||
| 287 | static struct i2c_board_info palmz72_i2c_device[] = { | ||
| 288 | { | ||
| 289 | I2C_BOARD_INFO("ov9640", 0x30), | ||
| 290 | } | ||
| 291 | }; | ||
| 292 | |||
| 293 | static int palmz72_camera_power(struct device *dev, int power) | ||
| 294 | { | ||
| 295 | gpio_set_value(GPIO_NR_PALMZ72_CAM_PWDN, !power); | ||
| 296 | mdelay(50); | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | static int palmz72_camera_reset(struct device *dev) | ||
| 301 | { | ||
| 302 | gpio_set_value(GPIO_NR_PALMZ72_CAM_RESET, 1); | ||
| 303 | mdelay(50); | ||
| 304 | gpio_set_value(GPIO_NR_PALMZ72_CAM_RESET, 0); | ||
| 305 | mdelay(50); | ||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | |||
| 309 | static struct soc_camera_link palmz72_iclink = { | ||
| 310 | .bus_id = 0, /* Match id in pxa27x_device_camera in device.c */ | ||
| 311 | .board_info = &palmz72_i2c_device[0], | ||
| 312 | .i2c_adapter_id = 0, | ||
| 313 | .module_name = "ov96xx", | ||
| 314 | .power = &palmz72_camera_power, | ||
| 315 | .reset = &palmz72_camera_reset, | ||
| 316 | .flags = SOCAM_DATAWIDTH_8, | ||
| 317 | }; | ||
| 318 | |||
| 319 | static struct gpiod_lookup_table palmz72_i2c_gpiod_table = { | ||
| 320 | .dev_id = "i2c-gpio.0", | ||
| 321 | .table = { | ||
| 322 | GPIO_LOOKUP_IDX("gpio-pxa", 118, NULL, 0, | ||
| 323 | GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), | ||
| 324 | GPIO_LOOKUP_IDX("gpio-pxa", 117, NULL, 1, | ||
| 325 | GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), | ||
| 326 | }, | ||
| 327 | }; | ||
| 328 | |||
| 329 | static struct i2c_gpio_platform_data palmz72_i2c_bus_data = { | ||
| 330 | .udelay = 10, | ||
| 331 | .timeout = 100, | ||
| 332 | }; | ||
| 333 | |||
| 334 | static struct platform_device palmz72_i2c_bus_device = { | ||
| 335 | .name = "i2c-gpio", | ||
| 336 | .id = 0, /* we use this as a replacement for i2c-pxa */ | ||
| 337 | .dev = { | ||
| 338 | .platform_data = &palmz72_i2c_bus_data, | ||
| 339 | } | ||
| 340 | }; | ||
| 341 | |||
| 342 | static struct platform_device palmz72_camera = { | ||
| 343 | .name = "soc-camera-pdrv", | ||
| 344 | .id = -1, | ||
| 345 | .dev = { | ||
| 346 | .platform_data = &palmz72_iclink, | ||
| 347 | }, | ||
| 348 | }; | ||
| 349 | |||
| 350 | /* Here we request the camera GPIOs and configure them. We power up the camera | ||
| 351 | * module, deassert the reset pin, but put it into powerdown (low to no power | ||
| 352 | * consumption) mode. This allows us to later bring the module up fast. */ | ||
| 353 | static struct gpio palmz72_camera_gpios[] = { | ||
| 354 | { GPIO_NR_PALMZ72_CAM_POWER, GPIOF_INIT_HIGH,"Camera DVDD" }, | ||
| 355 | { GPIO_NR_PALMZ72_CAM_RESET, GPIOF_INIT_LOW, "Camera RESET" }, | ||
| 356 | { GPIO_NR_PALMZ72_CAM_PWDN, GPIOF_INIT_LOW, "Camera PWDN" }, | ||
| 357 | }; | ||
| 358 | |||
| 359 | static inline void __init palmz72_cam_gpio_init(void) | ||
| 360 | { | ||
| 361 | int ret; | ||
| 362 | |||
| 363 | ret = gpio_request_array(ARRAY_AND_SIZE(palmz72_camera_gpios)); | ||
| 364 | if (!ret) | ||
| 365 | gpio_free_array(ARRAY_AND_SIZE(palmz72_camera_gpios)); | ||
| 366 | else | ||
| 367 | printk(KERN_ERR "Camera GPIO init failed!\n"); | ||
| 368 | |||
| 369 | return; | ||
| 370 | } | ||
| 371 | |||
| 372 | static void __init palmz72_camera_init(void) | ||
| 373 | { | ||
| 374 | palmz72_cam_gpio_init(); | ||
| 375 | pxa_set_camera_info(&palmz72_pxacamera_platform_data); | ||
| 376 | gpiod_add_lookup_table(&palmz72_i2c_gpiod_table); | ||
| 377 | platform_device_register(&palmz72_i2c_bus_device); | ||
| 378 | platform_device_register(&palmz72_camera); | ||
| 379 | } | ||
| 380 | #else | ||
| 381 | static inline void palmz72_camera_init(void) {} | ||
| 382 | #endif | ||
| 383 | |||
| 384 | static struct gpiod_lookup_table palmz72_mci_gpio_table = { | 273 | static struct gpiod_lookup_table palmz72_mci_gpio_table = { |
| 385 | .dev_id = "pxa2xx-mci.0", | 274 | .dev_id = "pxa2xx-mci.0", |
| 386 | .table = { | 275 | .table = { |
| @@ -416,7 +305,6 @@ static void __init palmz72_init(void) · 29 unmodified lines | |||
| 416 | palm27x_pmic_init(); | 305 | palm27x_pmic_init(); |
| 417 | palmz72_kpc_init(); | 306 | palmz72_kpc_init(); |
| 418 | palmz72_leds_init(); | 307 | palmz72_leds_init(); |
| 419 | palmz72_camera_init(); | ||
| 420 | } | 308 | } |
| 421 | 309 | ||
| 422 | MACHINE_START(PALMZ72, "Palm Zire72") | 310 | MACHINE_START(PALMZ72, "Palm Zire72") |
| @@ -24,10 +24,6 @@ · 23 unmodified lines | |||
| 24 | #include <linux/pwm.h> | 24 | #include <linux/pwm.h> |
| 25 | #include <linux/pwm_backlight.h> | 25 | #include <linux/pwm_backlight.h> |
| 26 | 26 | ||
| 27 | #include <media/i2c/mt9v022.h> | ||
| 28 | #include <media/soc_camera.h> | ||
| 29 | |||
| 30 | #include <linux/platform_data/media/camera-pxa.h> | ||
| 31 | #include <asm/mach/map.h> | 27 | #include <asm/mach/map.h> |
| 32 | #include "pxa27x.h" | 28 | #include "pxa27x.h" |
| 33 | #include <mach/audio.h> | 29 | #include <mach/audio.h> |
| @@ -374,149 +370,6 @@ static struct pxaohci_platform_data pcm990_ohci_platform_data = { · 340 unmodified lines | |||
| 374 | .power_on_delay = 10, | 370 | .power_on_delay = 10, |
| 375 | }; | 371 | }; |
| 376 | 372 | ||
| 377 | /* | ||
| 378 | * PXA27x Camera specific stuff | ||
| 379 | */ | ||
| 380 | #if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE) | ||
| 381 | static unsigned long pcm990_camera_pin_config[] = { | ||
| 382 | /* CIF */ | ||
| 383 | GPIO98_CIF_DD_0, | ||
| 384 | GPIO105_CIF_DD_1, | ||
| 385 | GPIO104_CIF_DD_2, | ||
| 386 | GPIO103_CIF_DD_3, | ||
| 387 | GPIO95_CIF_DD_4, | ||
| 388 | GPIO94_CIF_DD_5, | ||
| 389 | GPIO93_CIF_DD_6, | ||
| 390 | GPIO108_CIF_DD_7, | ||
| 391 | GPIO107_CIF_DD_8, | ||
| 392 | GPIO106_CIF_DD_9, | ||
| 393 | GPIO42_CIF_MCLK, | ||
| 394 | GPIO45_CIF_PCLK, | ||
| 395 | GPIO43_CIF_FV, | ||
| 396 | GPIO44_CIF_LV, | ||
| 397 | }; | ||
| 398 | |||
| 399 | /* | ||
| 400 | * CICR4: PCLK_EN: Pixel clock is supplied by the sensor | ||
| 401 | * MCLK_EN: Master clock is generated by PXA | ||
| 402 | * PCP: Data sampled on the falling edge of pixel clock | ||
| 403 | */ | ||
| 404 | struct pxacamera_platform_data pcm990_pxacamera_platform_data = { | ||
| 405 | .flags = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 | PXA_CAMERA_DATAWIDTH_10 | | ||
| 406 | PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN/* | PXA_CAMERA_PCP*/, | ||
| 407 | .mclk_10khz = 1000, | ||
| 408 | }; | ||
| 409 | |||
| 410 | #include <linux/platform_data/pca953x.h> | ||
| 411 | |||
| 412 | static struct pca953x_platform_data pca9536_data = { | ||
| 413 | .gpio_base = PXA_NR_BUILTIN_GPIO, | ||
| 414 | }; | ||
| 415 | |||
| 416 | static int gpio_bus_switch = -EINVAL; | ||
| 417 | |||
| 418 | static int pcm990_camera_set_bus_param(struct soc_camera_link *link, | ||
| 419 | unsigned long flags) | ||
| 420 | { | ||
| 421 | if (gpio_bus_switch < 0) { | ||
| 422 | if (flags == SOCAM_DATAWIDTH_10) | ||
| 423 | return 0; | ||
| 424 | else | ||
| 425 | return -EINVAL; | ||
| 426 | } | ||
| 427 | |||
| 428 | if (flags & SOCAM_DATAWIDTH_8) | ||
| 429 | gpio_set_value_cansleep(gpio_bus_switch, 1); | ||
| 430 | else | ||
| 431 | gpio_set_value_cansleep(gpio_bus_switch, 0); | ||
| 432 | |||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link) | ||
| 437 | { | ||
| 438 | int ret; | ||
| 439 | |||
| 440 | if (gpio_bus_switch < 0) { | ||
| 441 | ret = gpio_request(PXA_NR_BUILTIN_GPIO, "camera"); | ||
| 442 | if (!ret) { | ||
| 443 | gpio_bus_switch = PXA_NR_BUILTIN_GPIO; | ||
| 444 | gpio_direction_output(gpio_bus_switch, 0); | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | if (gpio_bus_switch >= 0) | ||
| 449 | return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10; | ||
| 450 | else | ||
| 451 | return SOCAM_DATAWIDTH_10; | ||
| 452 | } | ||
| 453 | |||
| 454 | static void pcm990_camera_free_bus(struct soc_camera_link *link) | ||
| 455 | { | ||
| 456 | if (gpio_bus_switch < 0) | ||
| 457 | return; | ||
| 458 | |||
| 459 | gpio_free(gpio_bus_switch); | ||
| 460 | gpio_bus_switch = -EINVAL; | ||
| 461 | } | ||
| 462 | |||
| 463 | /* Board I2C devices. */ | ||
| 464 | static struct i2c_board_info __initdata pcm990_i2c_devices[] = { | ||
| 465 | { | ||
| 466 | /* Must initialize before the camera(s) */ | ||
| 467 | I2C_BOARD_INFO("pca9536", 0x41), | ||
| 468 | .platform_data = &pca9536_data, | ||
| 469 | }, | ||
| 470 | }; | ||
| 471 | |||
| 472 | static struct mt9v022_platform_data mt9v022_pdata = { | ||
| 473 | .y_skip_top = 1, | ||
| 474 | }; | ||
| 475 | |||
| 476 | static struct i2c_board_info pcm990_camera_i2c[] = { | ||
| 477 | { | ||
| 478 | I2C_BOARD_INFO("mt9v022", 0x48), | ||
| 479 | }, { | ||
| 480 | I2C_BOARD_INFO("mt9m001", 0x5d), | ||
| 481 | }, | ||
| 482 | }; | ||
| 483 | |||
| 484 | static struct soc_camera_link iclink[] = { | ||
| 485 | { | ||
| 486 | .bus_id = 0, /* Must match with the camera ID */ | ||
| 487 | .board_info = &pcm990_camera_i2c[0], | ||
| 488 | .priv = &mt9v022_pdata, | ||
| 489 | .i2c_adapter_id = 0, | ||
| 490 | .query_bus_param = pcm990_camera_query_bus_param, | ||
| 491 | .set_bus_param = pcm990_camera_set_bus_param, | ||
| 492 | .free_bus = pcm990_camera_free_bus, | ||
| 493 | }, { | ||
| 494 | .bus_id = 0, /* Must match with the camera ID */ | ||
| 495 | .board_info = &pcm990_camera_i2c[1], | ||
| 496 | .i2c_adapter_id = 0, | ||
| 497 | .query_bus_param = pcm990_camera_query_bus_param, | ||
| 498 | .set_bus_param = pcm990_camera_set_bus_param, | ||
| 499 | .free_bus = pcm990_camera_free_bus, | ||
| 500 | }, | ||
| 501 | }; | ||
| 502 | |||
| 503 | static struct platform_device pcm990_camera[] = { | ||
| 504 | { | ||
| 505 | .name = "soc-camera-pdrv", | ||
| 506 | .id = 0, | ||
| 507 | .dev = { | ||
| 508 | .platform_data = &iclink[0], | ||
| 509 | }, | ||
| 510 | }, { | ||
| 511 | .name = "soc-camera-pdrv", | ||
| 512 | .id = 1, | ||
| 513 | .dev = { | ||
| 514 | .platform_data = &iclink[1], | ||
| 515 | }, | ||
| 516 | }, | ||
| 517 | }; | ||
| 518 | #endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */ | ||
| 519 | |||
| 520 | /* | 373 | /* |
| 521 | * system init for baseboard usage. Will be called by pcm027 init. | 374 | * system init for baseboard usage. Will be called by pcm027 init. |
| 522 | * | 375 | * |
| @@ -551,15 +404,5 @@ void __init pcm990_baseboard_init(void) · 28 unmodified lines | |||
| 551 | pxa_set_i2c_info(NULL); | 404 | pxa_set_i2c_info(NULL); |
| 552 | pxa_set_ac97_info(NULL); | 405 | pxa_set_ac97_info(NULL); |
| 553 | 406 | ||
| 554 | #if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE) | ||
| 555 | pxa2xx_mfp_config(ARRAY_AND_SIZE(pcm990_camera_pin_config)); | ||
| 556 | pxa_set_camera_info(&pcm990_pxacamera_platform_data); | ||
| 557 | |||
| 558 | i2c_register_board_info(0, ARRAY_AND_SIZE(pcm990_i2c_devices)); | ||
| 559 | |||
| 560 | platform_device_register(&pcm990_camera[0]); | ||
| 561 | platform_device_register(&pcm990_camera[1]); | ||
| 562 | #endif | ||
| 563 | |||
| 564 | printk(KERN_INFO "PCM-990 Evaluation baseboard initialized\n"); | 407 | printk(KERN_INFO "PCM-990 Evaluation baseboard initialized\n"); |
| 565 | } | 408 | } |
| @@ -65,9 +65,6 @@ CONFIG_VIDEO_DEV=y · 64 unmodified lines | |||
| 65 | # CONFIG_VIDEO_ALLOW_V4L1 is not set | 65 | # CONFIG_VIDEO_ALLOW_V4L1 is not set |
| 66 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set | 66 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set |
| 67 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y | 67 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y |
| 68 | CONFIG_SOC_CAMERA=y | ||
| 69 | CONFIG_SOC_CAMERA_PLATFORM=y | ||
| 70 | CONFIG_SOC_CAMERA_OV772X=y | ||
| 71 | CONFIG_VIDEO_SH_MOBILE_CEU=y | 68 | CONFIG_VIDEO_SH_MOBILE_CEU=y |
| 72 | # CONFIG_RADIO_ADAPTERS is not set | 69 | # CONFIG_RADIO_ADAPTERS is not set |
| 73 | CONFIG_FB=y | 70 | CONFIG_FB=y |
| @@ -72,9 +72,6 @@ CONFIG_MEDIA_SUPPORT=y · 71 unmodified lines | |||
| 72 | CONFIG_VIDEO_DEV=y | 72 | CONFIG_VIDEO_DEV=y |
| 73 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set | 73 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set |
| 74 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y | 74 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y |
| 75 | CONFIG_SOC_CAMERA=y | ||
| 76 | CONFIG_SOC_CAMERA_MT9T112=y | ||
| 77 | CONFIG_SOC_CAMERA_TW9910=y | ||
| 78 | CONFIG_VIDEO_SH_MOBILE_CEU=y | 75 | CONFIG_VIDEO_SH_MOBILE_CEU=y |
| 79 | # CONFIG_V4L_USB_DRIVERS is not set | 76 | # CONFIG_V4L_USB_DRIVERS is not set |
| 80 | CONFIG_FB=y | 77 | CONFIG_FB=y |
| @@ -62,9 +62,6 @@ CONFIG_VIDEO_DEV=y · 61 unmodified lines | |||
| 62 | # CONFIG_VIDEO_ALLOW_V4L1 is not set | 62 | # CONFIG_VIDEO_ALLOW_V4L1 is not set |
| 63 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set | 63 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set |
| 64 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y | 64 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y |
| 65 | CONFIG_SOC_CAMERA=y | ||
| 66 | CONFIG_SOC_CAMERA_TW9910=y | ||
| 67 | CONFIG_SOC_CAMERA_OV772X=y | ||
| 68 | CONFIG_VIDEO_SH_MOBILE_CEU=y | 65 | CONFIG_VIDEO_SH_MOBILE_CEU=y |
| 69 | # CONFIG_RADIO_ADAPTERS is not set | 66 | # CONFIG_RADIO_ADAPTERS is not set |
| 70 | CONFIG_FB=y | 67 | CONFIG_FB=y |
| @@ -70,8 +70,6 @@ CONFIG_VIDEO_DEV=y · 69 unmodified lines | |||
| 70 | CONFIG_DVB_CORE=m | 70 | CONFIG_DVB_CORE=m |
| 71 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set | 71 | # CONFIG_MEDIA_TUNER_CUSTOMISE is not set |
| 72 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y | 72 | CONFIG_VIDEO_HELPER_CHIPS_AUTO=y |
| 73 | CONFIG_SOC_CAMERA=y | ||
| 74 | CONFIG_SOC_CAMERA_OV772X=y | ||
| 75 | CONFIG_VIDEO_SH_MOBILE_CEU=y | 73 | CONFIG_VIDEO_SH_MOBILE_CEU=y |
| 76 | # CONFIG_RADIO_ADAPTERS is not set | 74 | # CONFIG_RADIO_ADAPTERS is not set |
| 77 | # CONFIG_DVB_FE_CUSTOMISE is not set | 75 | # CONFIG_DVB_FE_CUSTOMISE is not set |
| @@ -33,6 +33,7 @@ menuconfig MEDIA_CEC_SUPPORT · 32 unmodified lines | |||
| 33 | adapter that supports HDMI CEC. | 33 | adapter that supports HDMI CEC. |
| 34 | 34 | ||
| 35 | if MEDIA_CEC_SUPPORT | 35 | if MEDIA_CEC_SUPPORT |
| 36 | source "drivers/media/cec/i2c/Kconfig" | ||
| 36 | source "drivers/media/cec/platform/Kconfig" | 37 | source "drivers/media/cec/platform/Kconfig" |
| 37 | source "drivers/media/cec/usb/Kconfig" | 38 | source "drivers/media/cec/usb/Kconfig" |
| 38 | endif | 39 | endif |
| @@ -1,2 +1,2 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | obj-y += core/ platform/ usb/ | 2 | obj-y += core/ i2c/ platform/ usb/ |
| @@ -1306,7 +1306,6 @@ static int cec_config_log_addr(struct cec_adapter *adap, · 1305 unmodified lines | |||
| 1306 | 1306 | ||
| 1307 | las->log_addr[idx] = log_addr; | 1307 | las->log_addr[idx] = log_addr; |
| 1308 | las->log_addr_mask |= 1 << log_addr; | 1308 | las->log_addr_mask |= 1 << log_addr; |
| 1309 | adap->phys_addrs[log_addr] = adap->phys_addr; | ||
| 1310 | return 1; | 1309 | return 1; |
| 1311 | } | 1310 | } |
| 1312 | 1311 | ||
| @@ -1324,7 +1323,6 @@ static void cec_adap_unconfigure(struct cec_adapter *adap) · 11 unmodified lines | |||
| 1324 | adap->log_addrs.log_addr_mask = 0; | 1323 | adap->log_addrs.log_addr_mask = 0; |
| 1325 | adap->is_configuring = false; | 1324 | adap->is_configuring = false; |
| 1326 | adap->is_configured = false; | 1325 | adap->is_configured = false; |
| 1327 | memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); | ||
| 1328 | cec_flush(adap); | 1326 | cec_flush(adap); |
| 1329 | wake_up_interruptible(&adap->kthread_waitq); | 1327 | wake_up_interruptible(&adap->kthread_waitq); |
| 1330 | cec_post_state_event(adap); | 1328 | cec_post_state_event(adap); |
| @@ -1974,8 +1972,6 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, · 643 unmodified lines | |||
| 1974 | case CEC_MSG_REPORT_PHYSICAL_ADDR: { | 1972 | case CEC_MSG_REPORT_PHYSICAL_ADDR: { |
| 1975 | u16 pa = (msg->msg[2] << 8) | msg->msg[3]; | 1973 | u16 pa = (msg->msg[2] << 8) | msg->msg[3]; |
| 1976 | 1974 | ||
| 1977 | if (!from_unregistered) | ||
| 1978 | adap->phys_addrs[init_laddr] = pa; | ||
| 1979 | dprintk(1, "reported physical address %x.%x.%x.%x for logical address %d\n", | 1975 | dprintk(1, "reported physical address %x.%x.%x.%x for logical address %d\n", |
| 1980 | cec_phys_addr_exp(pa), init_laddr); | 1976 | cec_phys_addr_exp(pa), init_laddr); |
| 1981 | break; | 1977 | break; |
| @@ -147,7 +147,13 @@ static long cec_adap_g_log_addrs(struct cec_adapter *adap, · 146 unmodified lines | |||
| 147 | struct cec_log_addrs log_addrs; | 147 | struct cec_log_addrs log_addrs; |
| 148 | 148 | ||
| 149 | mutex_lock(&adap->lock); | 149 | mutex_lock(&adap->lock); |
| 150 | log_addrs = adap->log_addrs; | 150 | /* |
| 151 | * We use memcpy here instead of assignment since there is a | ||
| 152 | * hole at the end of struct cec_log_addrs that an assignment | ||
| 153 | * might ignore. So when we do copy_to_user() we could leak | ||
| 154 | * one byte of memory. | ||
| 155 | */ | ||
| 156 | memcpy(&log_addrs, &adap->log_addrs, sizeof(log_addrs)); | ||
| 151 | if (!adap->is_configured) | 157 | if (!adap->is_configured) |
| 152 | memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID, | 158 | memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID, |
| 153 | sizeof(log_addrs.log_addr)); | 159 | sizeof(log_addrs.log_addr)); |
| @@ -265,7 +265,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, · 264 unmodified lines | |||
| 265 | adap->sequence = 0; | 265 | adap->sequence = 0; |
| 266 | adap->ops = ops; | 266 | adap->ops = ops; |
| 267 | adap->priv = priv; | 267 | adap->priv = priv; |
| 268 | memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); | ||
| 269 | mutex_init(&adap->lock); | 268 | mutex_init(&adap->lock); |
| 270 | INIT_LIST_HEAD(&adap->transmit_queue); | 269 | INIT_LIST_HEAD(&adap->transmit_queue); |
| 271 | INIT_LIST_HEAD(&adap->wait_queue); | 270 | INIT_LIST_HEAD(&adap->wait_queue); |
| @@ -116,7 +116,8 @@ cec_notifier_conn_register(struct device *hdmi_dev, const char *port_name, · 115 unmodified lines | |||
| 116 | else | 116 | else |
| 117 | memset(&n->conn_info, 0, sizeof(n->conn_info)); | 117 | memset(&n->conn_info, 0, sizeof(n->conn_info)); |
| 118 | if (n->cec_adap) { | 118 | if (n->cec_adap) { |
| 119 | cec_phys_addr_invalidate(n->cec_adap); | 119 | if (!n->cec_adap->adap_controls_phys_addr) |
| 120 | cec_phys_addr_invalidate(n->cec_adap); | ||
| 120 | cec_s_conn_info(n->cec_adap, conn_info); | 121 | cec_s_conn_info(n->cec_adap, conn_info); |
| 121 | } | 122 | } |
| 122 | mutex_unlock(&n->lock); | 123 | mutex_unlock(&n->lock); |
| @@ -133,7 +134,8 @@ void cec_notifier_conn_unregister(struct cec_notifier *n) · 10 unmodified lines | |||
| 133 | memset(&n->conn_info, 0, sizeof(n->conn_info)); | 134 | memset(&n->conn_info, 0, sizeof(n->conn_info)); |
| 134 | n->phys_addr = CEC_PHYS_ADDR_INVALID; | 135 | n->phys_addr = CEC_PHYS_ADDR_INVALID; |
| 135 | if (n->cec_adap) { | 136 | if (n->cec_adap) { |
| 136 | cec_phys_addr_invalidate(n->cec_adap); | 137 | if (!n->cec_adap->adap_controls_phys_addr) |
| 138 | cec_phys_addr_invalidate(n->cec_adap); | ||
| 137 | cec_s_conn_info(n->cec_adap, NULL); | 139 | cec_s_conn_info(n->cec_adap, NULL); |
| 138 | } | 140 | } |
| 139 | mutex_unlock(&n->lock); | 141 | mutex_unlock(&n->lock); |
| @@ -158,7 +160,8 @@ cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *port_name, · 18 unmodified lines | |||
| 158 | n->cec_adap = adap; | 160 | n->cec_adap = adap; |
| 159 | adap->conn_info = n->conn_info; | 161 | adap->conn_info = n->conn_info; |
| 160 | adap->notifier = n; | 162 | adap->notifier = n; |
| 161 | cec_s_phys_addr(adap, n->phys_addr, false); | 163 | if (!adap->adap_controls_phys_addr) |
| 164 | cec_s_phys_addr(adap, n->phys_addr, false); | ||
| 162 | mutex_unlock(&n->lock); | 165 | mutex_unlock(&n->lock); |
| 163 | return n; | 166 | return n; |
| 164 | } | 167 | } |
| @@ -185,7 +188,7 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) · 20 unmodified lines | |||
| 185 | 188 | ||
| 186 | mutex_lock(&n->lock); | 189 | mutex_lock(&n->lock); |
| 187 | n->phys_addr = pa; | 190 | n->phys_addr = pa; |
| 188 | if (n->cec_adap) | 191 | if (n->cec_adap && !n->cec_adap->adap_controls_phys_addr) |
| 189 | cec_s_phys_addr(n->cec_adap, n->phys_addr, false); | 192 | cec_s_phys_addr(n->cec_adap, n->phys_addr, false); |
| 190 | mutex_unlock(&n->lock); | 193 | mutex_unlock(&n->lock); |
| 191 | } | 194 | } |
| @@ -0,0 +1,14 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | # | ||
| 3 | # I2C drivers | ||
| 4 | |||
| 5 | config CEC_CH7322 | ||
| 6 | tristate "Chrontel CH7322 CEC controller" | ||
| 7 | depends on I2C | ||
| 8 | select REGMAP_I2C | ||
| 9 | select CEC_CORE | ||
| 10 | help | ||
| 11 | This is a driver for the Chrontel CH7322 CEC controller. It uses the | ||
| 12 | generic CEC framework interface. | ||
| 13 | CEC bus is present in the HDMI connector and enables communication | ||
| 14 | between compatible devices. | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | # | ||
| 3 | # Makefile for the CEC I2C device drivers. | ||
| 4 | # | ||
| 5 | obj-$(CONFIG_CEC_CH7322) += ch7322.o | ||
| @@ -0,0 +1,604 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Driver for the Chrontel CH7322 CEC Controller | ||
| 4 | * | ||
| 5 | * Copyright 2020 Google LLC. | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * Notes | ||
| 10 | * | ||
| 11 | * - This device powers on in Auto Mode which has limited functionality. This | ||
| 12 | * driver disables Auto Mode when it attaches. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/cec.h> | ||
| 17 | #include <linux/dmi.h> | ||
| 18 | #include <linux/i2c.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/mutex.h> | ||
| 22 | #include <linux/pci.h> | ||
| 23 | #include <linux/regmap.h> | ||
| 24 | #include <media/cec.h> | ||
| 25 | #include <media/cec-notifier.h> | ||
| 26 | |||
| 27 | #define CH7322_WRITE 0x00 | ||
| 28 | #define CH7322_WRITE_MSENT 0x80 | ||
| 29 | #define CH7322_WRITE_BOK 0x40 | ||
| 30 | #define CH7322_WRITE_NMASK 0x0f | ||
| 31 | |||
| 32 | /* Write buffer is 0x01-0x10 */ | ||
| 33 | #define CH7322_WRBUF 0x01 | ||
| 34 | #define CH7322_WRBUF_LEN 0x10 | ||
| 35 | |||
| 36 | #define CH7322_READ 0x40 | ||
| 37 | #define CH7322_READ_NRDT 0x80 | ||
| 38 | #define CH7322_READ_MSENT 0x20 | ||
| 39 | #define CH7322_READ_NMASK 0x0f | ||
| 40 | |||
| 41 | /* Read buffer is 0x41-0x50 */ | ||
| 42 | #define CH7322_RDBUF 0x41 | ||
| 43 | #define CH7322_RDBUF_LEN 0x10 | ||
| 44 | |||
| 45 | #define CH7322_MODE 0x11 | ||
| 46 | #define CH7322_MODE_AUTO 0x78 | ||
| 47 | #define CH7322_MODE_SW 0xb5 | ||
| 48 | |||
| 49 | #define CH7322_RESET 0x12 | ||
| 50 | #define CH7322_RESET_RST 0x00 | ||
| 51 | |||
| 52 | #define CH7322_POWER 0x13 | ||
| 53 | #define CH7322_POWER_FPD 0x04 | ||
| 54 | |||
| 55 | #define CH7322_CFG0 0x17 | ||
| 56 | #define CH7322_CFG0_EOBEN 0x40 | ||
| 57 | #define CH7322_CFG0_PEOB 0x20 | ||
| 58 | #define CH7322_CFG0_CLRSPP 0x10 | ||
| 59 | #define CH7322_CFG0_FLOW 0x08 | ||
| 60 | |||
| 61 | #define CH7322_CFG1 0x1a | ||
| 62 | #define CH7322_CFG1_STDBYO 0x04 | ||
| 63 | #define CH7322_CFG1_HPBP 0x02 | ||
| 64 | #define CH7322_CFG1_PIO 0x01 | ||
| 65 | |||
| 66 | #define CH7322_INTCTL 0x1b | ||
| 67 | #define CH7322_INTCTL_INTPB 0x80 | ||
| 68 | #define CH7322_INTCTL_STDBY 0x40 | ||
| 69 | #define CH7322_INTCTL_HPDFALL 0x20 | ||
| 70 | #define CH7322_INTCTL_HPDRISE 0x10 | ||
| 71 | #define CH7322_INTCTL_RXMSG 0x08 | ||
| 72 | #define CH7322_INTCTL_TXMSG 0x04 | ||
| 73 | #define CH7322_INTCTL_NEWPHA 0x02 | ||
| 74 | #define CH7322_INTCTL_ERROR 0x01 | ||
| 75 | |||
| 76 | #define CH7322_DVCLKFNH 0x1d | ||
| 77 | #define CH7322_DVCLKFNL 0x1e | ||
| 78 | |||
| 79 | #define CH7322_CTL 0x31 | ||
| 80 | #define CH7322_CTL_FSTDBY 0x80 | ||
| 81 | #define CH7322_CTL_PLSEN 0x40 | ||
| 82 | #define CH7322_CTL_PLSPB 0x20 | ||
| 83 | #define CH7322_CTL_SPADL 0x10 | ||
| 84 | #define CH7322_CTL_HINIT 0x08 | ||
| 85 | #define CH7322_CTL_WPHYA 0x04 | ||
| 86 | #define CH7322_CTL_H1T 0x02 | ||
| 87 | #define CH7322_CTL_S1T 0x01 | ||
| 88 | |||
| 89 | #define CH7322_PAWH 0x32 | ||
| 90 | #define CH7322_PAWL 0x33 | ||
| 91 | |||
| 92 | #define CH7322_ADDLW 0x34 | ||
| 93 | #define CH7322_ADDLW_MASK 0xf0 | ||
| 94 | |||
| 95 | #define CH7322_ADDLR 0x3d | ||
| 96 | #define CH7322_ADDLR_HPD 0x80 | ||
| 97 | #define CH7322_ADDLR_MASK 0x0f | ||
| 98 | |||
| 99 | #define CH7322_INTDATA 0x3e | ||
| 100 | #define CH7322_INTDATA_MODE 0x80 | ||
| 101 | #define CH7322_INTDATA_STDBY 0x40 | ||
| 102 | #define CH7322_INTDATA_HPDFALL 0x20 | ||
| 103 | #define CH7322_INTDATA_HPDRISE 0x10 | ||
| 104 | #define CH7322_INTDATA_RXMSG 0x08 | ||
| 105 | #define CH7322_INTDATA_TXMSG 0x04 | ||
| 106 | #define CH7322_INTDATA_NEWPHA 0x02 | ||
| 107 | #define CH7322_INTDATA_ERROR 0x01 | ||
| 108 | |||
| 109 | #define CH7322_EVENT 0x3f | ||
| 110 | #define CH7322_EVENT_TXERR 0x80 | ||
| 111 | #define CH7322_EVENT_HRST 0x40 | ||
| 112 | #define CH7322_EVENT_HFST 0x20 | ||
| 113 | #define CH7322_EVENT_PHACHG 0x10 | ||
| 114 | #define CH7322_EVENT_ACTST 0x08 | ||
| 115 | #define CH7322_EVENT_PHARDY 0x04 | ||
| 116 | #define CH7322_EVENT_BSOK 0x02 | ||
| 117 | #define CH7322_EVENT_ERRADCF 0x01 | ||
| 118 | |||
| 119 | #define CH7322_DID 0x51 | ||
| 120 | #define CH7322_DID_CH7322 0x5b | ||
| 121 | #define CH7322_DID_CH7323 0x5f | ||
| 122 | |||
| 123 | #define CH7322_REVISIONID 0x52 | ||
| 124 | |||
| 125 | #define CH7322_PARH 0x53 | ||
| 126 | #define CH7322_PARL 0x54 | ||
| 127 | |||
| 128 | #define CH7322_IOCFG2 0x75 | ||
| 129 | #define CH7322_IOCFG_CIO 0x80 | ||
| 130 | #define CH7322_IOCFG_IOCFGMASK 0x78 | ||
| 131 | #define CH7322_IOCFG_AUDIO 0x04 | ||
| 132 | #define CH7322_IOCFG_SPAMST 0x02 | ||
| 133 | #define CH7322_IOCFG_SPAMSP 0x01 | ||
| 134 | |||
| 135 | #define CH7322_CTL3 0x7b | ||
| 136 | #define CH7322_CTL3_SWENA 0x80 | ||
| 137 | #define CH7322_CTL3_FC_INIT 0x40 | ||
| 138 | #define CH7322_CTL3_SML_FL 0x20 | ||
| 139 | #define CH7322_CTL3_SM_RDST 0x10 | ||
| 140 | #define CH7322_CTL3_SPP_CIAH 0x08 | ||
| 141 | #define CH7322_CTL3_SPP_CIAL 0x04 | ||
| 142 | #define CH7322_CTL3_SPP_ACTH 0x02 | ||
| 143 | #define CH7322_CTL3_SPP_ACTL 0x01 | ||
| 144 | |||
| 145 | /* BOK status means NACK */ | ||
| 146 | #define CH7322_TX_FLAG_NACK BIT(0) | ||
| 147 | /* Device will retry automatically */ | ||
| 148 | #define CH7322_TX_FLAG_RETRY BIT(1) | ||
| 149 | |||
| 150 | struct ch7322 { | ||
| 151 | struct i2c_client *i2c; | ||
| 152 | struct regmap *regmap; | ||
| 153 | struct cec_adapter *cec; | ||
| 154 | struct mutex mutex; /* device access mutex */ | ||
| 155 | u8 tx_flags; | ||
| 156 | }; | ||
| 157 | |||
| 158 | static const struct regmap_config ch7322_regmap = { | ||
| 159 | .reg_bits = 8, | ||
| 160 | .val_bits = 8, | ||
| 161 | .max_register = 0x7f, | ||
| 162 | .disable_locking = true, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static int ch7322_send_message(struct ch7322 *ch7322, const struct cec_msg *msg) | ||
| 166 | { | ||
| 167 | unsigned int val; | ||
| 168 | unsigned int len = msg->len; | ||
| 169 | int ret; | ||
| 170 | int i; | ||
| 171 | |||
| 172 | WARN_ON(!mutex_is_locked(&ch7322->mutex)); | ||
| 173 | |||
| 174 | if (len > CH7322_WRBUF_LEN || len < 1) | ||
| 175 | return -EINVAL; | ||
| 176 | |||
| 177 | ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val); | ||
| 178 | if (ret) | ||
| 179 | return ret; | ||
| 180 | |||
| 181 | /* Buffer not ready */ | ||
| 182 | if (!(val & CH7322_WRITE_MSENT)) | ||
| 183 | return -EBUSY; | ||
| 184 | |||
| 185 | if (cec_msg_opcode(msg) == -1 && | ||
| 186 | cec_msg_initiator(msg) == cec_msg_destination(msg)) { | ||
| 187 | ch7322->tx_flags = CH7322_TX_FLAG_NACK | CH7322_TX_FLAG_RETRY; | ||
| 188 | } else if (cec_msg_is_broadcast(msg)) { | ||
| 189 | ch7322->tx_flags = CH7322_TX_FLAG_NACK; | ||
| 190 | } else { | ||
| 191 | ch7322->tx_flags = CH7322_TX_FLAG_RETRY; | ||
| 192 | } | ||
| 193 | |||
| 194 | ret = regmap_write(ch7322->regmap, CH7322_WRITE, len - 1); | ||
| 195 | if (ret) | ||
| 196 | return ret; | ||
| 197 | |||
| 198 | for (i = 0; i < len; i++) { | ||
| 199 | ret = regmap_write(ch7322->regmap, | ||
| 200 | CH7322_WRBUF + i, msg->msg[i]); | ||
| 201 | if (ret) | ||
| 202 | return ret; | ||
| 203 | } | ||
| 204 | |||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int ch7322_receive_message(struct ch7322 *ch7322, struct cec_msg *msg) | ||
| 209 | { | ||
| 210 | unsigned int val; | ||
| 211 | int ret = 0; | ||
| 212 | int i; | ||
| 213 | |||
| 214 | WARN_ON(!mutex_is_locked(&ch7322->mutex)); | ||
| 215 | |||
| 216 | ret = regmap_read(ch7322->regmap, CH7322_READ, &val); | ||
| 217 | if (ret) | ||
| 218 | return ret; | ||
| 219 | |||
| 220 | /* Message not ready */ | ||
| 221 | if (!(val & CH7322_READ_NRDT)) | ||
| 222 | return -EIO; | ||
| 223 | |||
| 224 | msg->len = (val & CH7322_READ_NMASK) + 1; | ||
| 225 | |||
| 226 | /* Read entire RDBUF to clear state */ | ||
| 227 | for (i = 0; i < CH7322_RDBUF_LEN; i++) { | ||
| 228 | ret = regmap_read(ch7322->regmap, CH7322_RDBUF + i, &val); | ||
| 229 | if (ret) | ||
| 230 | return ret; | ||
| 231 | msg->msg[i] = (u8)val; | ||
| 232 | } | ||
| 233 | |||
| 234 | return 0; | ||
| 235 | } | ||
| 236 | |||
| 237 | static void ch7322_tx_done(struct ch7322 *ch7322) | ||
| 238 | { | ||
| 239 | int ret; | ||
| 240 | unsigned int val; | ||
| 241 | u8 status, flags; | ||
| 242 | |||
| 243 | mutex_lock(&ch7322->mutex); | ||
| 244 | ret = regmap_read(ch7322->regmap, CH7322_WRITE, &val); | ||
| 245 | flags = ch7322->tx_flags; | ||
| 246 | mutex_unlock(&ch7322->mutex); | ||
| 247 | |||
| 248 | /* | ||
| 249 | * The device returns a one-bit OK status which usually means ACK but | ||
| 250 | * actually means NACK when sending a logical address query or a | ||
| 251 | * broadcast. | ||
| 252 | */ | ||
| 253 | if (ret) | ||
| 254 | status = CEC_TX_STATUS_ERROR; | ||
| 255 | else if ((val & CH7322_WRITE_BOK) && (flags & CH7322_TX_FLAG_NACK)) | ||
| 256 | status = CEC_TX_STATUS_NACK; | ||
| 257 | else if (val & CH7322_WRITE_BOK) | ||
| 258 | status = CEC_TX_STATUS_OK; | ||
| 259 | else if (flags & CH7322_TX_FLAG_NACK) | ||
| 260 | status = CEC_TX_STATUS_OK; | ||
| 261 | else | ||
| 262 | status = CEC_TX_STATUS_NACK; | ||
| 263 | |||
| 264 | if (status == CEC_TX_STATUS_NACK && (flags & CH7322_TX_FLAG_RETRY)) | ||
| 265 | status |= CEC_TX_STATUS_MAX_RETRIES; | ||
| 266 | |||
| 267 | cec_transmit_attempt_done(ch7322->cec, status); | ||
| 268 | } | ||
| 269 | |||
| 270 | static void ch7322_rx_done(struct ch7322 *ch7322) | ||
| 271 | { | ||
| 272 | struct cec_msg msg; | ||
| 273 | int ret; | ||
| 274 | |||
| 275 | mutex_lock(&ch7322->mutex); | ||
| 276 | ret = ch7322_receive_message(ch7322, &msg); | ||
| 277 | mutex_unlock(&ch7322->mutex); | ||
| 278 | |||
| 279 | if (ret) | ||
| 280 | dev_err(&ch7322->i2c->dev, "cec receive error: %d\n", ret); | ||
| 281 | else | ||
| 282 | cec_received_msg(ch7322->cec, &msg); | ||
| 283 | } | ||
| 284 | |||
| 285 | /* | ||
| 286 | * This device can either monitor the DDC lines to obtain the physical address | ||
| 287 | * or it can allow the host to program it. This driver lets the device obtain | ||
| 288 | * it. | ||
| 289 | */ | ||
| 290 | static void ch7322_phys_addr(struct ch7322 *ch7322) | ||
| 291 | { | ||
| 292 | unsigned int pah, pal; | ||
| 293 | int ret = 0; | ||
| 294 | |||
| 295 | mutex_lock(&ch7322->mutex); | ||
| 296 | ret |= regmap_read(ch7322->regmap, CH7322_PARH, &pah); | ||
| 297 | ret |= regmap_read(ch7322->regmap, CH7322_PARL, &pal); | ||
| 298 | mutex_unlock(&ch7322->mutex); | ||
| 299 | |||
| 300 | if (ret) | ||
| 301 | dev_err(&ch7322->i2c->dev, "phys addr error\n"); | ||
| 302 | else | ||
| 303 | cec_s_phys_addr(ch7322->cec, pal | (pah << 8), false); | ||
| 304 | } | ||
| 305 | |||
| 306 | static irqreturn_t ch7322_irq(int irq, void *dev) | ||
| 307 | { | ||
| 308 | struct ch7322 *ch7322 = dev; | ||
| 309 | unsigned int data = 0; | ||
| 310 | |||
| 311 | mutex_lock(&ch7322->mutex); | ||
| 312 | regmap_read(ch7322->regmap, CH7322_INTDATA, &data); | ||
| 313 | regmap_write(ch7322->regmap, CH7322_INTDATA, data); | ||
| 314 | mutex_unlock(&ch7322->mutex); | ||
| 315 | |||
| 316 | if (data & CH7322_INTDATA_HPDFALL) | ||
| 317 | cec_phys_addr_invalidate(ch7322->cec); | ||
| 318 | |||
| 319 | if (data & CH7322_INTDATA_TXMSG) | ||
| 320 | ch7322_tx_done(ch7322); | ||
| 321 | |||
| 322 | if (data & CH7322_INTDATA_RXMSG) | ||
| 323 | ch7322_rx_done(ch7322); | ||
| 324 | |||
| 325 | if (data & CH7322_INTDATA_NEWPHA) | ||
| 326 | ch7322_phys_addr(ch7322); | ||
| 327 | |||
| 328 | if (data & CH7322_INTDATA_ERROR) | ||
| 329 | dev_dbg(&ch7322->i2c->dev, "unknown error\n"); | ||
| 330 | |||
| 331 | return IRQ_HANDLED; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* This device is always enabled */ | ||
| 335 | static int ch7322_cec_adap_enable(struct cec_adapter *adap, bool enable) | ||
| 336 | { | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | static int ch7322_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) | ||
| 341 | { | ||
| 342 | struct ch7322 *ch7322 = cec_get_drvdata(adap); | ||
| 343 | int ret; | ||
| 344 | |||
| 345 | mutex_lock(&ch7322->mutex); | ||
| 346 | ret = regmap_update_bits(ch7322->regmap, CH7322_ADDLW, | ||
| 347 | CH7322_ADDLW_MASK, log_addr << 4); | ||
| 348 | mutex_unlock(&ch7322->mutex); | ||
| 349 | |||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 353 | static int ch7322_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | ||
| 354 | u32 signal_free_time, struct cec_msg *msg) | ||
| 355 | { | ||
| 356 | struct ch7322 *ch7322 = cec_get_drvdata(adap); | ||
| 357 | int ret; | ||
| 358 | |||
| 359 | mutex_lock(&ch7322->mutex); | ||
| 360 | ret = ch7322_send_message(ch7322, msg); | ||
| 361 | mutex_unlock(&ch7322->mutex); | ||
| 362 | |||
| 363 | return ret; | ||
| 364 | } | ||
| 365 | |||
| 366 | static const struct cec_adap_ops ch7322_cec_adap_ops = { | ||
| 367 | .adap_enable = ch7322_cec_adap_enable, | ||
| 368 | .adap_log_addr = ch7322_cec_adap_log_addr, | ||
| 369 | .adap_transmit = ch7322_cec_adap_transmit, | ||
| 370 | }; | ||
| 371 | |||
| 372 | #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) | ||
| 373 | |||
| 374 | struct ch7322_conn_match { | ||
| 375 | const char *dev_name; | ||
| 376 | const char *pci_name; | ||
| 377 | const char *port_name; | ||
| 378 | }; | ||
| 379 | |||
| 380 | static struct ch7322_conn_match google_endeavour[] = { | ||
| 381 | { "i2c-PRP0001:00", "0000:00:02.0", "Port B" }, | ||
| 382 | { "i2c-PRP0001:01", "0000:00:02.0", "Port C" }, | ||
| 383 | { }, | ||
| 384 | }; | ||
| 385 | |||
| 386 | static const struct dmi_system_id ch7322_dmi_table[] = { | ||
| 387 | { | ||
| 388 | .matches = { | ||
| 389 | DMI_MATCH(DMI_BOARD_VENDOR, "Google"), | ||
| 390 | DMI_MATCH(DMI_BOARD_NAME, "Endeavour"), | ||
| 391 | }, | ||
| 392 | .driver_data = google_endeavour, | ||
| 393 | }, | ||
| 394 | { }, | ||
| 395 | }; | ||
| 396 | |||
| 397 | /* Make a best-effort attempt to locate a matching HDMI port */ | ||
| 398 | static int ch7322_get_port(struct i2c_client *client, | ||
| 399 | struct device **dev, | ||
| 400 | const char **port) | ||
| 401 | { | ||
| 402 | const struct dmi_system_id *system; | ||
| 403 | const struct ch7322_conn_match *conn; | ||
| 404 | |||
| 405 | *dev = NULL; | ||
| 406 | *port = NULL; | ||
| 407 | |||
| 408 | system = dmi_first_match(ch7322_dmi_table); | ||
| 409 | if (!system) | ||
| 410 | return 0; | ||
| 411 | |||
| 412 | for (conn = system->driver_data; conn->dev_name; conn++) { | ||
| 413 | if (!strcmp(dev_name(&client->dev), conn->dev_name)) { | ||
| 414 | struct device *d; | ||
| 415 | |||
| 416 | d = bus_find_device_by_name(&pci_bus_type, NULL, | ||
| 417 | conn->pci_name); | ||
| 418 | if (!d) | ||
| 419 | return -EPROBE_DEFER; | ||
| 420 | |||
| 421 | put_device(d); | ||
| 422 | |||
| 423 | *dev = d; | ||
| 424 | *port = conn->port_name; | ||
| 425 | |||
| 426 | return 0; | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | return 0; | ||
| 431 | } | ||
| 432 | |||
| 433 | #else | ||
| 434 | |||
| 435 | static int ch7322_get_port(struct i2c_client *client, | ||
| 436 | struct device **dev, | ||
| 437 | const char **port) | ||
| 438 | { | ||
| 439 | *dev = NULL; | ||
| 440 | *port = NULL; | ||
| 441 | |||
| 442 | return 0; | ||
| 443 | } | ||
| 444 | |||
| 445 | #endif | ||
| 446 | |||
| 447 | static int ch7322_probe(struct i2c_client *client) | ||
| 448 | { | ||
| 449 | struct device *hdmi_dev; | ||
| 450 | const char *port_name; | ||
| 451 | struct ch7322 *ch7322; | ||
| 452 | struct cec_notifier *notifier = NULL; | ||
| 453 | u32 caps = CEC_CAP_DEFAULTS; | ||
| 454 | int ret; | ||
| 455 | unsigned int val; | ||
| 456 | |||
| 457 | ret = ch7322_get_port(client, &hdmi_dev, &port_name); | ||
| 458 | if (ret) | ||
| 459 | return ret; | ||
| 460 | |||
| 461 | if (hdmi_dev) | ||
| 462 | caps |= CEC_CAP_CONNECTOR_INFO; | ||
| 463 | |||
| 464 | ch7322 = devm_kzalloc(&client->dev, sizeof(*ch7322), GFP_KERNEL); | ||
| 465 | if (!ch7322) | ||
| 466 | return -ENOMEM; | ||
| 467 | |||
| 468 | ch7322->regmap = devm_regmap_init_i2c(client, &ch7322_regmap); | ||
| 469 | if (IS_ERR(ch7322->regmap)) | ||
| 470 | return PTR_ERR(ch7322->regmap); | ||
| 471 | |||
| 472 | ret = regmap_read(ch7322->regmap, CH7322_DID, &val); | ||
| 473 | if (ret) | ||
| 474 | return ret; | ||
| 475 | |||
| 476 | if (val != CH7322_DID_CH7322) | ||
| 477 | return -EOPNOTSUPP; | ||
| 478 | |||
| 479 | mutex_init(&ch7322->mutex); | ||
| 480 | ch7322->i2c = client; | ||
| 481 | ch7322->tx_flags = 0; | ||
| 482 | |||
| 483 | i2c_set_clientdata(client, ch7322); | ||
| 484 | |||
| 485 | /* Disable auto mode */ | ||
| 486 | ret = regmap_write(ch7322->regmap, CH7322_MODE, CH7322_MODE_SW); | ||
| 487 | if (ret) | ||
| 488 | goto err_mutex; | ||
| 489 | |||
| 490 | /* Enable logical address register */ | ||
| 491 | ret = regmap_update_bits(ch7322->regmap, CH7322_CTL, | ||
| 492 | CH7322_CTL_SPADL, CH7322_CTL_SPADL); | ||
| 493 | if (ret) | ||
| 494 | goto err_mutex; | ||
| 495 | |||
| 496 | ch7322->cec = cec_allocate_adapter(&ch7322_cec_adap_ops, ch7322, | ||
| 497 | dev_name(&client->dev), | ||
| 498 | caps, 1); | ||
| 499 | |||
| 500 | if (IS_ERR(ch7322->cec)) { | ||
| 501 | ret = PTR_ERR(ch7322->cec); | ||
| 502 | goto err_mutex; | ||
| 503 | } | ||
| 504 | |||
| 505 | ch7322->cec->adap_controls_phys_addr = true; | ||
| 506 | |||
| 507 | if (hdmi_dev) { | ||
| 508 | notifier = cec_notifier_cec_adap_register(hdmi_dev, | ||
| 509 | port_name, | ||
| 510 | ch7322->cec); | ||
| 511 | if (!notifier) { | ||
| 512 | ret = -ENOMEM; | ||
| 513 | goto err_cec; | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | /* Configure, mask, and clear interrupt */ | ||
| 518 | ret = regmap_write(ch7322->regmap, CH7322_CFG1, 0); | ||
| 519 | if (ret) | ||
| 520 | goto err_notifier; | ||
| 521 | ret = regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB); | ||
| 522 | if (ret) | ||
| 523 | goto err_notifier; | ||
| 524 | ret = regmap_write(ch7322->regmap, CH7322_INTDATA, 0xff); | ||
| 525 | if (ret) | ||
| 526 | goto err_notifier; | ||
| 527 | |||
| 528 | /* If HPD is up read physical address */ | ||
| 529 | ret = regmap_read(ch7322->regmap, CH7322_ADDLR, &val); | ||
| 530 | if (ret) | ||
| 531 | goto err_notifier; | ||
| 532 | if (val & CH7322_ADDLR_HPD) | ||
| 533 | ch7322_phys_addr(ch7322); | ||
| 534 | |||
| 535 | ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, | ||
| 536 | ch7322_irq, | ||
| 537 | IRQF_ONESHOT | IRQF_TRIGGER_RISING, | ||
| 538 | client->name, ch7322); | ||
| 539 | if (ret) | ||
| 540 | goto err_notifier; | ||
| 541 | |||
| 542 | /* Unmask interrupt */ | ||
| 543 | mutex_lock(&ch7322->mutex); | ||
| 544 | ret = regmap_write(ch7322->regmap, CH7322_INTCTL, 0xff); | ||
| 545 | mutex_unlock(&ch7322->mutex); | ||
| 546 | |||
| 547 | if (ret) | ||
| 548 | goto err_notifier; | ||
| 549 | |||
| 550 | ret = cec_register_adapter(ch7322->cec, &client->dev); | ||
| 551 | if (ret) | ||
| 552 | goto err_notifier; | ||
| 553 | |||
| 554 | dev_info(&client->dev, "device registered\n"); | ||
| 555 | |||
| 556 | return 0; | ||
| 557 | |||
| 558 | err_notifier: | ||
| 559 | if (notifier) | ||
| 560 | cec_notifier_cec_adap_unregister(notifier, ch7322->cec); | ||
| 561 | err_cec: | ||
| 562 | cec_delete_adapter(ch7322->cec); | ||
| 563 | err_mutex: | ||
| 564 | mutex_destroy(&ch7322->mutex); | ||
| 565 | return ret; | ||
| 566 | } | ||
| 567 | |||
| 568 | static int ch7322_remove(struct i2c_client *client) | ||
| 569 | { | ||
| 570 | struct ch7322 *ch7322 = i2c_get_clientdata(client); | ||
| 571 | |||
| 572 | /* Mask interrupt */ | ||
| 573 | mutex_lock(&ch7322->mutex); | ||
| 574 | regmap_write(ch7322->regmap, CH7322_INTCTL, CH7322_INTCTL_INTPB); | ||
| 575 | mutex_unlock(&ch7322->mutex); | ||
| 576 | |||
| 577 | cec_unregister_adapter(ch7322->cec); | ||
| 578 | mutex_destroy(&ch7322->mutex); | ||
| 579 | |||
| 580 | dev_info(&client->dev, "device unregistered\n"); | ||
| 581 | |||
| 582 | return 0; | ||
| 583 | } | ||
| 584 | |||
| 585 | static const struct of_device_id ch7322_of_match[] = { | ||
| 586 | { .compatible = "chrontel,ch7322", }, | ||
| 587 | {}, | ||
| 588 | }; | ||
| 589 | MODULE_DEVICE_TABLE(of, ch7322_of_match); | ||
| 590 | |||
| 591 | static struct i2c_driver ch7322_i2c_driver = { | ||
| 592 | .driver = { | ||
| 593 | .name = "ch7322", | ||
| 594 | .of_match_table = of_match_ptr(ch7322_of_match), | ||
| 595 | }, | ||
| 596 | .probe_new = ch7322_probe, | ||
| 597 | .remove = ch7322_remove, | ||
| 598 | }; | ||
| 599 | |||
| 600 | module_i2c_driver(ch7322_i2c_driver); | ||
| 601 | |||
| 602 | MODULE_DESCRIPTION("Chrontel CH7322 CEC Controller Driver"); | ||
| 603 | MODULE_AUTHOR("Jeff Chase <jnchase@google.com>"); | ||
| 604 | MODULE_LICENSE("GPL"); | ||
| @@ -277,11 +277,7 @@ static int cros_ec_cec_probe(struct platform_device *pdev) · 276 unmodified lines | |||
| 277 | platform_set_drvdata(pdev, cros_ec_cec); | 277 | platform_set_drvdata(pdev, cros_ec_cec); |
| 278 | cros_ec_cec->cros_ec = cros_ec; | 278 | cros_ec_cec->cros_ec = cros_ec; |
| 279 | 279 | ||
| 280 | ret = device_init_wakeup(&pdev->dev, 1); | 280 | device_init_wakeup(&pdev->dev, 1); |
| 281 | if (ret) { | ||
| 282 | dev_err(&pdev->dev, "failed to initialize wakeup\n"); | ||
| 283 | return ret; | ||
| 284 | } | ||
| 285 | 281 | ||
| 286 | cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, | 282 | cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, |
| 287 | DRV_NAME, | 283 | DRV_NAME, |
| @@ -1927,44 +1927,46 @@ typedef struct { u16 __; u8 _; } __packed x24; · 1926 unmodified lines | |||
| 1927 | 1927 | ||
| 1928 | static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | 1928 | static noinline void tpg_print_str_2(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], |
| 1929 | unsigned p, unsigned first, unsigned div, unsigned step, | 1929 | unsigned p, unsigned first, unsigned div, unsigned step, |
| 1930 | int y, int x, char *text, unsigned len) | 1930 | int y, int x, const char *text, unsigned len) |
| 1931 | { | 1931 | { |
| 1932 | PRINTSTR(u8); | 1932 | PRINTSTR(u8); |
| 1933 | } | 1933 | } |
| 1934 | 1934 | ||
| 1935 | static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | 1935 | static noinline void tpg_print_str_4(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], |
| 1936 | unsigned p, unsigned first, unsigned div, unsigned step, | 1936 | unsigned p, unsigned first, unsigned div, unsigned step, |
| 1937 | int y, int x, char *text, unsigned len) | 1937 | int y, int x, const char *text, unsigned len) |
| 1938 | { | 1938 | { |
| 1939 | PRINTSTR(u16); | 1939 | PRINTSTR(u16); |
| 1940 | } | 1940 | } |
| 1941 | 1941 | ||
| 1942 | static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | 1942 | static noinline void tpg_print_str_6(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], |
| 1943 | unsigned p, unsigned first, unsigned div, unsigned step, | 1943 | unsigned p, unsigned first, unsigned div, unsigned step, |
| 1944 | int y, int x, char *text, unsigned len) | 1944 | int y, int x, const char *text, unsigned len) |
| 1945 | { | 1945 | { |
| 1946 | PRINTSTR(x24); | 1946 | PRINTSTR(x24); |
| 1947 | } | 1947 | } |
| 1948 | 1948 | ||
| 1949 | static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | 1949 | static noinline void tpg_print_str_8(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], |
| 1950 | unsigned p, unsigned first, unsigned div, unsigned step, | 1950 | unsigned p, unsigned first, unsigned div, unsigned step, |
| 1951 | int y, int x, char *text, unsigned len) | 1951 | int y, int x, const char *text, unsigned len) |
| 1952 | { | 1952 | { |
| 1953 | PRINTSTR(u32); | 1953 | PRINTSTR(u32); |
| 1954 | } | 1954 | } |
| 1955 | 1955 | ||
| 1956 | void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], | 1956 | void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], |
| 1957 | int y, int x, char *text) | 1957 | int y, int x, const char *text) |
| 1958 | { | 1958 | { |
| 1959 | unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; | 1959 | unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; |
| 1960 | unsigned div = step; | 1960 | unsigned div = step; |
| 1961 | unsigned first = 0; | 1961 | unsigned first = 0; |
| 1962 | unsigned len = strlen(text); | 1962 | unsigned len; |
| 1963 | unsigned p; | 1963 | unsigned p; |
| 1964 | 1964 | ||
| 1965 | if (font8x16 == NULL || basep == NULL) | 1965 | if (font8x16 == NULL || basep == NULL || text == NULL) |
| 1966 | return; | 1966 | return; |
| 1967 | 1967 | ||
| 1968 | len = strlen(text); | ||
| 1969 | |||
| 1968 | /* Checks if it is possible to show string */ | 1970 | /* Checks if it is possible to show string */ |
| 1969 | if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width) | 1971 | if (y + 16 >= tpg->compose.height || x + 8 >= tpg->compose.width) |
| 1970 | return; | 1972 | return; |
| @@ -2006,6 +2008,30 @@ void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], · 35 unmodified lines | |||
| 2006 | } | 2008 | } |
| 2007 | EXPORT_SYMBOL_GPL(tpg_gen_text); | 2009 | EXPORT_SYMBOL_GPL(tpg_gen_text); |
| 2008 | 2010 | ||
| 2011 | const char *tpg_g_color_order(const struct tpg_data *tpg) | ||
| 2012 | { | ||
| 2013 | switch (tpg->pattern) { | ||
| 2014 | case TPG_PAT_75_COLORBAR: | ||
| 2015 | case TPG_PAT_100_COLORBAR: | ||
| 2016 | case TPG_PAT_CSC_COLORBAR: | ||
| 2017 | case TPG_PAT_100_HCOLORBAR: | ||
| 2018 | return "White, yellow, cyan, green, magenta, red, blue, black"; | ||
| 2019 | case TPG_PAT_BLACK: | ||
| 2020 | return "Black"; | ||
| 2021 | case TPG_PAT_WHITE: | ||
| 2022 | return "White"; | ||
| 2023 | case TPG_PAT_RED: | ||
| 2024 | return "Red"; | ||
| 2025 | case TPG_PAT_GREEN: | ||
| 2026 | return "Green"; | ||
| 2027 | case TPG_PAT_BLUE: | ||
| 2028 | return "Blue"; | ||
| 2029 | default: | ||
| 2030 | return NULL; | ||
| 2031 | } | ||
| 2032 | } | ||
| 2033 | EXPORT_SYMBOL_GPL(tpg_g_color_order); | ||
| 2034 | |||
| 2009 | void tpg_update_mv_step(struct tpg_data *tpg) | 2035 | void tpg_update_mv_step(struct tpg_data *tpg) |
| 2010 | { | 2036 | { |
| 2011 | int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1; | 2037 | int factor = tpg->mv_hor_mode > TPG_MOVE_NONE ? -1 : 1; |
| @@ -34,10 +34,11 @@ · 33 unmodified lines | |||
| 34 | static int debug; | 34 | static int debug; |
| 35 | module_param(debug, int, 0644); | 35 | module_param(debug, int, 0644); |
| 36 | 36 | ||
| 37 | #define dprintk(level, fmt, arg...) \ | 37 | #define dprintk(q, level, fmt, arg...) \ |
| 38 | do { \ | 38 | do { \ |
| 39 | if (debug >= level) \ | 39 | if (debug >= level) \ |
| 40 | pr_info("%s: " fmt, __func__, ## arg); \ | 40 | pr_info("[%s] %s: " fmt, (q)->name, __func__, \ |
| 41 | ## arg); \ | ||
| 41 | } while (0) | 42 | } while (0) |
| 42 | 43 | ||
| 43 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 44 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| @@ -51,8 +52,8 @@ module_param(debug, int, 0644); · 7 unmodified lines | |||
| 51 | */ | 52 | */ |
| 52 | 53 | ||
| 53 | #define log_memop(vb, op) \ | 54 | #define log_memop(vb, op) \ |
| 54 | dprintk(2, "call_memop(%p, %d, %s)%s\n", \ | 55 | dprintk((vb)->vb2_queue, 2, "call_memop(%d, %s)%s\n", \ |
| 55 | (vb)->vb2_queue, (vb)->index, #op, \ | 56 | (vb)->index, #op, \ |
| 56 | (vb)->vb2_queue->mem_ops->op ? "" : " (nop)") | 57 | (vb)->vb2_queue->mem_ops->op ? "" : " (nop)") |
| 57 | 58 | ||
| 58 | #define call_memop(vb, op, args...) \ | 59 | #define call_memop(vb, op, args...) \ |
| @@ -90,7 +91,7 @@ module_param(debug, int, 0644); · 31 unmodified lines | |||
| 90 | }) | 91 | }) |
| 91 | 92 | ||
| 92 | #define log_qop(q, op) \ | 93 | #define log_qop(q, op) \ |
| 93 | dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ | 94 | dprintk(q, 2, "call_qop(%s)%s\n", #op, \ |
| 94 | (q)->ops->op ? "" : " (nop)") | 95 | (q)->ops->op ? "" : " (nop)") |
| 95 | 96 | ||
| 96 | #define call_qop(q, op, args...) \ | 97 | #define call_qop(q, op, args...) \ |
| @@ -113,8 +114,8 @@ module_param(debug, int, 0644); · 16 unmodified lines | |||
| 113 | }) | 114 | }) |
| 114 | 115 | ||
| 115 | #define log_vb_qop(vb, op, args...) \ | 116 | #define log_vb_qop(vb, op, args...) \ |
| 116 | dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ | 117 | dprintk((vb)->vb2_queue, 2, "call_vb_qop(%d, %s)%s\n", \ |
| 117 | (vb)->vb2_queue, (vb)->index, #op, \ | 118 | (vb)->index, #op, \ |
| 118 | (vb)->vb2_queue->ops->op ? "" : " (nop)") | 119 | (vb)->vb2_queue->ops->op ? "" : " (nop)") |
| 119 | 120 | ||
| 120 | #define call_vb_qop(vb, op, args...) \ | 121 | #define call_vb_qop(vb, op, args...) \ |
| @@ -190,6 +191,23 @@ module_param(debug, int, 0644); · 69 unmodified lines | |||
| 190 | static void __vb2_queue_cancel(struct vb2_queue *q); | 191 | static void __vb2_queue_cancel(struct vb2_queue *q); |
| 191 | static void __enqueue_in_driver(struct vb2_buffer *vb); | 192 | static void __enqueue_in_driver(struct vb2_buffer *vb); |
| 192 | 193 | ||
| 194 | static const char *vb2_state_name(enum vb2_buffer_state s) | ||
| 195 | { | ||
| 196 | static const char * const state_names[] = { | ||
| 197 | [VB2_BUF_STATE_DEQUEUED] = "dequeued", | ||
| 198 | [VB2_BUF_STATE_IN_REQUEST] = "in request", | ||
| 199 | [VB2_BUF_STATE_PREPARING] = "preparing", | ||
| 200 | [VB2_BUF_STATE_QUEUED] = "queued", | ||
| 201 | [VB2_BUF_STATE_ACTIVE] = "active", | ||
| 202 | [VB2_BUF_STATE_DONE] = "done", | ||
| 203 | [VB2_BUF_STATE_ERROR] = "error", | ||
| 204 | }; | ||
| 205 | |||
| 206 | if ((unsigned int)(s) < ARRAY_SIZE(state_names)) | ||
| 207 | return state_names[s]; | ||
| 208 | return "unknown"; | ||
| 209 | } | ||
| 210 | |||
| 193 | /* | 211 | /* |
| 194 | * __vb2_buf_mem_alloc() - allocate video memory for the given buffer | 212 | * __vb2_buf_mem_alloc() - allocate video memory for the given buffer |
| 195 | */ | 213 | */ |
| @@ -246,7 +264,8 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) · 50 unmodified lines | |||
| 246 | for (plane = 0; plane < vb->num_planes; ++plane) { | 264 | for (plane = 0; plane < vb->num_planes; ++plane) { |
| 247 | call_void_memop(vb, put, vb->planes[plane].mem_priv); | 265 | call_void_memop(vb, put, vb->planes[plane].mem_priv); |
| 248 | vb->planes[plane].mem_priv = NULL; | 266 | vb->planes[plane].mem_priv = NULL; |
| 249 | dprintk(3, "freed plane %d of buffer %d\n", plane, vb->index); | 267 | dprintk(vb->vb2_queue, 3, "freed plane %d of buffer %d\n", |
| 268 | plane, vb->index); | ||
| 250 | } | 269 | } |
| 251 | } | 270 | } |
| 252 | 271 | ||
| @@ -296,6 +315,44 @@ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) · 43 unmodified lines | |||
| 296 | __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); | 315 | __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); |
| 297 | } | 316 | } |
| 298 | 317 | ||
| 318 | /* | ||
| 319 | * __vb2_buf_mem_prepare() - call ->prepare() on buffer's private memory | ||
| 320 | * to sync caches | ||
| 321 | */ | ||
| 322 | static void __vb2_buf_mem_prepare(struct vb2_buffer *vb) | ||
| 323 | { | ||
| 324 | unsigned int plane; | ||
| 325 | |||
| 326 | if (vb->synced) | ||
| 327 | return; | ||
| 328 | |||
| 329 | if (vb->need_cache_sync_on_prepare) { | ||
| 330 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
| 331 | call_void_memop(vb, prepare, | ||
| 332 | vb->planes[plane].mem_priv); | ||
| 333 | } | ||
| 334 | vb->synced = 1; | ||
| 335 | } | ||
| 336 | |||
| 337 | /* | ||
| 338 | * __vb2_buf_mem_finish() - call ->finish on buffer's private memory | ||
| 339 | * to sync caches | ||
| 340 | */ | ||
| 341 | static void __vb2_buf_mem_finish(struct vb2_buffer *vb) | ||
| 342 | { | ||
| 343 | unsigned int plane; | ||
| 344 | |||
| 345 | if (!vb->synced) | ||
| 346 | return; | ||
| 347 | |||
| 348 | if (vb->need_cache_sync_on_finish) { | ||
| 349 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
| 350 | call_void_memop(vb, finish, | ||
| 351 | vb->planes[plane].mem_priv); | ||
| 352 | } | ||
| 353 | vb->synced = 0; | ||
| 354 | } | ||
| 355 | |||
| 299 | /* | 356 | /* |
| 300 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in | 357 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in |
| 301 | * the buffer. | 358 | * the buffer. |
| @@ -316,7 +373,7 @@ static void __setup_offsets(struct vb2_buffer *vb) · 14 unmodified lines | |||
| 316 | for (plane = 0; plane < vb->num_planes; ++plane) { | 373 | for (plane = 0; plane < vb->num_planes; ++plane) { |
| 317 | vb->planes[plane].m.offset = off; | 374 | vb->planes[plane].m.offset = off; |
| 318 | 375 | ||
| 319 | dprintk(3, "buffer %d, plane %d offset 0x%08lx\n", | 376 | dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n", |
| 320 | vb->index, plane, off); | 377 | vb->index, plane, off); |
| 321 | 378 | ||
| 322 | off += vb->planes[plane].length; | 379 | off += vb->planes[plane].length; |
| @@ -347,7 +404,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 24 unmodified lines | |||
| 347 | /* Allocate videobuf buffer structures */ | 404 | /* Allocate videobuf buffer structures */ |
| 348 | vb = kzalloc(q->buf_struct_size, GFP_KERNEL); | 405 | vb = kzalloc(q->buf_struct_size, GFP_KERNEL); |
| 349 | if (!vb) { | 406 | if (!vb) { |
| 350 | dprintk(1, "memory alloc for buffer struct failed\n"); | 407 | dprintk(q, 1, "memory alloc for buffer struct failed\n"); |
| 351 | break; | 408 | break; |
| 352 | } | 409 | } |
| 353 | 410 | ||
| @@ -369,7 +426,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 15 unmodified lines | |||
| 369 | if (memory == VB2_MEMORY_MMAP) { | 426 | if (memory == VB2_MEMORY_MMAP) { |
| 370 | ret = __vb2_buf_mem_alloc(vb); | 427 | ret = __vb2_buf_mem_alloc(vb); |
| 371 | if (ret) { | 428 | if (ret) { |
| 372 | dprintk(1, "failed allocating memory for buffer %d\n", | 429 | dprintk(q, 1, "failed allocating memory for buffer %d\n", |
| 373 | buffer); | 430 | buffer); |
| 374 | q->bufs[vb->index] = NULL; | 431 | q->bufs[vb->index] = NULL; |
| 375 | kfree(vb); | 432 | kfree(vb); |
| @@ -383,7 +440,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 7 unmodified lines | |||
| 383 | */ | 440 | */ |
| 384 | ret = call_vb_qop(vb, buf_init, vb); | 441 | ret = call_vb_qop(vb, buf_init, vb); |
| 385 | if (ret) { | 442 | if (ret) { |
| 386 | dprintk(1, "buffer %d %p initialization failed\n", | 443 | dprintk(q, 1, "buffer %d %p initialization failed\n", |
| 387 | buffer, vb); | 444 | buffer, vb); |
| 388 | __vb2_buf_mem_free(vb); | 445 | __vb2_buf_mem_free(vb); |
| 389 | q->bufs[vb->index] = NULL; | 446 | q->bufs[vb->index] = NULL; |
| @@ -393,7 +450,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 3 unmodified lines | |||
| 393 | } | 450 | } |
| 394 | } | 451 | } |
| 395 | 452 | ||
| 396 | dprintk(3, "allocated %d buffers, %d plane(s) each\n", | 453 | dprintk(q, 3, "allocated %d buffers, %d plane(s) each\n", |
| 397 | buffer, num_planes); | 454 | buffer, num_planes); |
| 398 | 455 | ||
| 399 | return buffer; | 456 | return buffer; |
| @@ -445,7 +502,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) · 45 unmodified lines | |||
| 445 | if (q->bufs[buffer] == NULL) | 502 | if (q->bufs[buffer] == NULL) |
| 446 | continue; | 503 | continue; |
| 447 | if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) { | 504 | if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) { |
| 448 | dprintk(1, "preparing buffers, cannot free\n"); | 505 | dprintk(q, 1, "preparing buffers, cannot free\n"); |
| 449 | return -EAGAIN; | 506 | return -EAGAIN; |
| 450 | } | 507 | } |
| 451 | } | 508 | } |
| @@ -623,12 +680,12 @@ int vb2_verify_memory_type(struct vb2_queue *q, · 171 unmodified lines | |||
| 623 | { | 680 | { |
| 624 | if (memory != VB2_MEMORY_MMAP && memory != VB2_MEMORY_USERPTR && | 681 | if (memory != VB2_MEMORY_MMAP && memory != VB2_MEMORY_USERPTR && |
| 625 | memory != VB2_MEMORY_DMABUF) { | 682 | memory != VB2_MEMORY_DMABUF) { |
| 626 | dprintk(1, "unsupported memory type\n"); | 683 | dprintk(q, 1, "unsupported memory type\n"); |
| 627 | return -EINVAL; | 684 | return -EINVAL; |
| 628 | } | 685 | } |
| 629 | 686 | ||
| 630 | if (type != q->type) { | 687 | if (type != q->type) { |
| 631 | dprintk(1, "requested type is incorrect\n"); | 688 | dprintk(q, 1, "requested type is incorrect\n"); |
| 632 | return -EINVAL; | 689 | return -EINVAL; |
| 633 | } | 690 | } |
| 634 | 691 | ||
| @@ -637,17 +694,17 @@ int vb2_verify_memory_type(struct vb2_queue *q, · 2 unmodified lines | |||
| 637 | * are available. | 694 | * are available. |
| 638 | */ | 695 | */ |
| 639 | if (memory == VB2_MEMORY_MMAP && __verify_mmap_ops(q)) { | 696 | if (memory == VB2_MEMORY_MMAP && __verify_mmap_ops(q)) { |
| 640 | dprintk(1, "MMAP for current setup unsupported\n"); | 697 | dprintk(q, 1, "MMAP for current setup unsupported\n"); |
| 641 | return -EINVAL; | 698 | return -EINVAL; |
| 642 | } | 699 | } |
| 643 | 700 | ||
| 644 | if (memory == VB2_MEMORY_USERPTR && __verify_userptr_ops(q)) { | 701 | if (memory == VB2_MEMORY_USERPTR && __verify_userptr_ops(q)) { |
| 645 | dprintk(1, "USERPTR for current setup unsupported\n"); | 702 | dprintk(q, 1, "USERPTR for current setup unsupported\n"); |
| 646 | return -EINVAL; | 703 | return -EINVAL; |
| 647 | } | 704 | } |
| 648 | 705 | ||
| 649 | if (memory == VB2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) { | 706 | if (memory == VB2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) { |
| 650 | dprintk(1, "DMABUF for current setup unsupported\n"); | 707 | dprintk(q, 1, "DMABUF for current setup unsupported\n"); |
| 651 | return -EINVAL; | 708 | return -EINVAL; |
| 652 | } | 709 | } |
| 653 | 710 | ||
| @@ -657,33 +714,59 @@ int vb2_verify_memory_type(struct vb2_queue *q, · 3 unmodified lines | |||
| 657 | * do the memory and type validation. | 714 | * do the memory and type validation. |
| 658 | */ | 715 | */ |
| 659 | if (vb2_fileio_is_active(q)) { | 716 | if (vb2_fileio_is_active(q)) { |
| 660 | dprintk(1, "file io in progress\n"); | 717 | dprintk(q, 1, "file io in progress\n"); |
| 661 | return -EBUSY; | 718 | return -EBUSY; |
| 662 | } | 719 | } |
| 663 | return 0; | 720 | return 0; |
| 664 | } | 721 | } |
| 665 | EXPORT_SYMBOL(vb2_verify_memory_type); | 722 | EXPORT_SYMBOL(vb2_verify_memory_type); |
| 666 | 723 | ||
| 724 | static void set_queue_consistency(struct vb2_queue *q, bool consistent_mem) | ||
| 725 | { | ||
| 726 | q->dma_attrs &= ~DMA_ATTR_NON_CONSISTENT; | ||
| 727 | |||
| 728 | if (!vb2_queue_allows_cache_hints(q)) | ||
| 729 | return; | ||
| 730 | if (!consistent_mem) | ||
| 731 | q->dma_attrs |= DMA_ATTR_NON_CONSISTENT; | ||
| 732 | } | ||
| 733 | |||
| 734 | static bool verify_consistency_attr(struct vb2_queue *q, bool consistent_mem) | ||
| 735 | { | ||
| 736 | bool queue_is_consistent = !(q->dma_attrs & DMA_ATTR_NON_CONSISTENT); | ||
| 737 | |||
| 738 | if (consistent_mem != queue_is_consistent) { | ||
| 739 | dprintk(q, 1, "memory consistency model mismatch\n"); | ||
| 740 | return false; | ||
| 741 | } | ||
| 742 | return true; | ||
| 743 | } | ||
| 744 | |||
| 667 | int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, | 745 | int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, |
| 668 | unsigned int *count) | 746 | unsigned int flags, unsigned int *count) |
| 669 | { | 747 | { |
| 670 | unsigned int num_buffers, allocated_buffers, num_planes = 0; | 748 | unsigned int num_buffers, allocated_buffers, num_planes = 0; |
| 671 | unsigned plane_sizes[VB2_MAX_PLANES] = { }; | 749 | unsigned plane_sizes[VB2_MAX_PLANES] = { }; |
| 750 | bool consistent_mem = true; | ||
| 672 | unsigned int i; | 751 | unsigned int i; |
| 673 | int ret; | 752 | int ret; |
| 674 | 753 | ||
| 754 | if (flags & V4L2_FLAG_MEMORY_NON_CONSISTENT) | ||
| 755 | consistent_mem = false; | ||
| 756 | |||
| 675 | if (q->streaming) { | 757 | if (q->streaming) { |
| 676 | dprintk(1, "streaming active\n"); | 758 | dprintk(q, 1, "streaming active\n"); |
| 677 | return -EBUSY; | 759 | return -EBUSY; |
| 678 | } | 760 | } |
| 679 | 761 | ||
| 680 | if (q->waiting_in_dqbuf && *count) { | 762 | if (q->waiting_in_dqbuf && *count) { |
| 681 | dprintk(1, "another dup()ped fd is waiting for a buffer\n"); | 763 | dprintk(q, 1, "another dup()ped fd is waiting for a buffer\n"); |
| 682 | return -EBUSY; | 764 | return -EBUSY; |
| 683 | } | 765 | } |
| 684 | 766 | ||
| 685 | if (*count == 0 || q->num_buffers != 0 || | 767 | if (*count == 0 || q->num_buffers != 0 || |
| 686 | (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) { | 768 | (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory) || |
| 769 | !verify_consistency_attr(q, consistent_mem)) { | ||
| 687 | /* | 770 | /* |
| 688 | * We already have buffers allocated, so first check if they | 771 | * We already have buffers allocated, so first check if they |
| 689 | * are not in use and can be freed. | 772 | * are not in use and can be freed. |
| @@ -691,7 +774,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 1 unmodified line | |||
| 691 | mutex_lock(&q->mmap_lock); | 774 | mutex_lock(&q->mmap_lock); |
| 692 | if (debug && q->memory == VB2_MEMORY_MMAP && | 775 | if (debug && q->memory == VB2_MEMORY_MMAP && |
| 693 | __buffers_in_use(q)) | 776 | __buffers_in_use(q)) |
| 694 | dprintk(1, "memory in use, orphaning buffers\n"); | 777 | dprintk(q, 1, "memory in use, orphaning buffers\n"); |
| 695 | 778 | ||
| 696 | /* | 779 | /* |
| 697 | * Call queue_cancel to clean up any buffers in the | 780 | * Call queue_cancel to clean up any buffers in the |
| @@ -720,6 +803,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 22 unmodified lines | |||
| 720 | num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME); | 803 | num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME); |
| 721 | memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); | 804 | memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); |
| 722 | q->memory = memory; | 805 | q->memory = memory; |
| 806 | set_queue_consistency(q, consistent_mem); | ||
| 723 | 807 | ||
| 724 | /* | 808 | /* |
| 725 | * Ask the driver how many buffers and planes per buffer it requires. | 809 | * Ask the driver how many buffers and planes per buffer it requires. |
| @@ -742,7 +826,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 16 unmodified lines | |||
| 742 | allocated_buffers = | 826 | allocated_buffers = |
| 743 | __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes); | 827 | __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes); |
| 744 | if (allocated_buffers == 0) { | 828 | if (allocated_buffers == 0) { |
| 745 | dprintk(1, "memory allocation failed\n"); | 829 | dprintk(q, 1, "memory allocation failed\n"); |
| 746 | return -ENOMEM; | 830 | return -ENOMEM; |
| 747 | } | 831 | } |
| 748 | 832 | ||
| @@ -804,29 +888,39 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, · 55 unmodified lines | |||
| 804 | EXPORT_SYMBOL_GPL(vb2_core_reqbufs); | 888 | EXPORT_SYMBOL_GPL(vb2_core_reqbufs); |
| 805 | 889 | ||
| 806 | int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, | 890 | int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, |
| 807 | unsigned int *count, unsigned requested_planes, | 891 | unsigned int flags, unsigned int *count, |
| 808 | const unsigned requested_sizes[]) | 892 | unsigned int requested_planes, |
| 893 | const unsigned int requested_sizes[]) | ||
| 809 | { | 894 | { |
| 810 | unsigned int num_planes = 0, num_buffers, allocated_buffers; | 895 | unsigned int num_planes = 0, num_buffers, allocated_buffers; |
| 811 | unsigned plane_sizes[VB2_MAX_PLANES] = { }; | 896 | unsigned plane_sizes[VB2_MAX_PLANES] = { }; |
| 897 | bool consistent_mem = true; | ||
| 812 | int ret; | 898 | int ret; |
| 813 | 899 | ||
| 900 | if (flags & V4L2_FLAG_MEMORY_NON_CONSISTENT) | ||
| 901 | consistent_mem = false; | ||
| 902 | |||
| 814 | if (q->num_buffers == VB2_MAX_FRAME) { | 903 | if (q->num_buffers == VB2_MAX_FRAME) { |
| 815 | dprintk(1, "maximum number of buffers already allocated\n"); | 904 | dprintk(q, 1, "maximum number of buffers already allocated\n"); |
| 816 | return -ENOBUFS; | 905 | return -ENOBUFS; |
| 817 | } | 906 | } |
| 818 | 907 | ||
| 819 | if (!q->num_buffers) { | 908 | if (!q->num_buffers) { |
| 820 | if (q->waiting_in_dqbuf && *count) { | 909 | if (q->waiting_in_dqbuf && *count) { |
| 821 | dprintk(1, "another dup()ped fd is waiting for a buffer\n"); | 910 | dprintk(q, 1, "another dup()ped fd is waiting for a buffer\n"); |
| 822 | return -EBUSY; | 911 | return -EBUSY; |
| 823 | } | 912 | } |
| 824 | memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); | 913 | memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); |
| 825 | q->memory = memory; | 914 | q->memory = memory; |
| 915 | set_queue_consistency(q, consistent_mem); | ||
| 826 | q->waiting_for_buffers = !q->is_output; | 916 | q->waiting_for_buffers = !q->is_output; |
| 827 | } else if (q->memory != memory) { | 917 | } else { |
| 828 | dprintk(1, "memory model mismatch\n"); | 918 | if (q->memory != memory) { |
| 829 | return -EINVAL; | 919 | dprintk(q, 1, "memory model mismatch\n"); |
| 920 | return -EINVAL; | ||
| 921 | } | ||
| 922 | if (!verify_consistency_attr(q, consistent_mem)) | ||
| 923 | return -EINVAL; | ||
| 830 | } | 924 | } |
| 831 | 925 | ||
| 832 | num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers); | 926 | num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers); |
| @@ -849,7 +943,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, · 16 unmodified lines | |||
| 849 | allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers, | 943 | allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers, |
| 850 | num_planes, plane_sizes); | 944 | num_planes, plane_sizes); |
| 851 | if (allocated_buffers == 0) { | 945 | if (allocated_buffers == 0) { |
| 852 | dprintk(1, "memory allocation failed\n"); | 946 | dprintk(q, 1, "memory allocation failed\n"); |
| 853 | return -ENOMEM; | 947 | return -ENOMEM; |
| 854 | } | 948 | } |
| 855 | 949 | ||
| @@ -922,7 +1016,6 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) · 66 unmodified lines | |||
| 922 | { | 1016 | { |
| 923 | struct vb2_queue *q = vb->vb2_queue; | 1017 | struct vb2_queue *q = vb->vb2_queue; |
| 924 | unsigned long flags; | 1018 | unsigned long flags; |
| 925 | unsigned int plane; | ||
| 926 | 1019 | ||
| 927 | if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE)) | 1020 | if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE)) |
| 928 | return; | 1021 | return; |
| @@ -939,15 +1032,11 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) · 10 unmodified lines | |||
| 939 | */ | 1032 | */ |
| 940 | vb->cnt_buf_done++; | 1033 | vb->cnt_buf_done++; |
| 941 | #endif | 1034 | #endif |
| 942 | dprintk(4, "done processing on buffer %d, state: %d\n", | 1035 | dprintk(q, 4, "done processing on buffer %d, state: %s\n", |
| 943 | vb->index, state); | 1036 | vb->index, vb2_state_name(state)); |
| 944 | 1037 | ||
| 945 | if (state != VB2_BUF_STATE_QUEUED) { | 1038 | if (state != VB2_BUF_STATE_QUEUED) |
| 946 | /* sync buffers */ | 1039 | __vb2_buf_mem_finish(vb); |
| 947 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
| 948 | call_void_memop(vb, finish, vb->planes[plane].mem_priv); | ||
| 949 | vb->synced = 0; | ||
| 950 | } | ||
| 951 | 1040 | ||
| 952 | spin_lock_irqsave(&q->done_lock, flags); | 1041 | spin_lock_irqsave(&q->done_lock, flags); |
| 953 | if (state == VB2_BUF_STATE_QUEUED) { | 1042 | if (state == VB2_BUF_STATE_QUEUED) { |
| @@ -1029,12 +1118,12 @@ static int __prepare_userptr(struct vb2_buffer *vb) · 75 unmodified lines | |||
| 1029 | && vb->planes[plane].length == planes[plane].length) | 1118 | && vb->planes[plane].length == planes[plane].length) |
| 1030 | continue; | 1119 | continue; |
| 1031 | 1120 | ||
| 1032 | dprintk(3, "userspace address for plane %d changed, reacquiring memory\n", | 1121 | dprintk(q, 3, "userspace address for plane %d changed, reacquiring memory\n", |
| 1033 | plane); | 1122 | plane); |
| 1034 | 1123 | ||
| 1035 | /* Check if the provided plane buffer is large enough */ | 1124 | /* Check if the provided plane buffer is large enough */ |
| 1036 | if (planes[plane].length < vb->planes[plane].min_length) { | 1125 | if (planes[plane].length < vb->planes[plane].min_length) { |
| 1037 | dprintk(1, "provided buffer size %u is less than setup size %u for plane %d\n", | 1126 | dprintk(q, 1, "provided buffer size %u is less than setup size %u for plane %d\n", |
| 1038 | planes[plane].length, | 1127 | planes[plane].length, |
| 1039 | vb->planes[plane].min_length, | 1128 | vb->planes[plane].min_length, |
| 1040 | plane); | 1129 | plane); |
| @@ -1064,7 +1153,7 @@ static int __prepare_userptr(struct vb2_buffer *vb) · 23 unmodified lines | |||
| 1064 | planes[plane].m.userptr, | 1153 | planes[plane].m.userptr, |
| 1065 | planes[plane].length, q->dma_dir); | 1154 | planes[plane].length, q->dma_dir); |
| 1066 | if (IS_ERR(mem_priv)) { | 1155 | if (IS_ERR(mem_priv)) { |
| 1067 | dprintk(1, "failed acquiring userspace memory for plane %d\n", | 1156 | dprintk(q, 1, "failed acquiring userspace memory for plane %d\n", |
| 1068 | plane); | 1157 | plane); |
| 1069 | ret = PTR_ERR(mem_priv); | 1158 | ret = PTR_ERR(mem_priv); |
| 1070 | goto err; | 1159 | goto err; |
| @@ -1091,14 +1180,14 @@ static int __prepare_userptr(struct vb2_buffer *vb) · 20 unmodified lines | |||
| 1091 | */ | 1180 | */ |
| 1092 | ret = call_vb_qop(vb, buf_init, vb); | 1181 | ret = call_vb_qop(vb, buf_init, vb); |
| 1093 | if (ret) { | 1182 | if (ret) { |
| 1094 | dprintk(1, "buffer initialization failed\n"); | 1183 | dprintk(q, 1, "buffer initialization failed\n"); |
| 1095 | goto err; | 1184 | goto err; |
| 1096 | } | 1185 | } |
| 1097 | } | 1186 | } |
| 1098 | 1187 | ||
| 1099 | ret = call_vb_qop(vb, buf_prepare, vb); | 1188 | ret = call_vb_qop(vb, buf_prepare, vb); |
| 1100 | if (ret) { | 1189 | if (ret) { |
| 1101 | dprintk(1, "buffer preparation failed\n"); | 1190 | dprintk(q, 1, "buffer preparation failed\n"); |
| 1102 | call_void_vb_qop(vb, buf_cleanup, vb); | 1191 | call_void_vb_qop(vb, buf_cleanup, vb); |
| 1103 | goto err; | 1192 | goto err; |
| 1104 | } | 1193 | } |
| @@ -1141,7 +1230,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) · 36 unmodified lines | |||
| 1141 | struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); | 1230 | struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); |
| 1142 | 1231 | ||
| 1143 | if (IS_ERR_OR_NULL(dbuf)) { | 1232 | if (IS_ERR_OR_NULL(dbuf)) { |
| 1144 | dprintk(1, "invalid dmabuf fd for plane %d\n", | 1233 | dprintk(q, 1, "invalid dmabuf fd for plane %d\n", |
| 1145 | plane); | 1234 | plane); |
| 1146 | ret = -EINVAL; | 1235 | ret = -EINVAL; |
| 1147 | goto err; | 1236 | goto err; |
| @@ -1152,7 +1241,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) · 4 unmodified lines | |||
| 1152 | planes[plane].length = dbuf->size; | 1241 | planes[plane].length = dbuf->size; |
| 1153 | 1242 | ||
| 1154 | if (planes[plane].length < vb->planes[plane].min_length) { | 1243 | if (planes[plane].length < vb->planes[plane].min_length) { |
| 1155 | dprintk(1, "invalid dmabuf length %u for plane %d, minimum length %u\n", | 1244 | dprintk(q, 1, "invalid dmabuf length %u for plane %d, minimum length %u\n", |
| 1156 | planes[plane].length, plane, | 1245 | planes[plane].length, plane, |
| 1157 | vb->planes[plane].min_length); | 1246 | vb->planes[plane].min_length); |
| 1158 | dma_buf_put(dbuf); | 1247 | dma_buf_put(dbuf); |
| @@ -1167,7 +1256,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) · 8 unmodified lines | |||
| 1167 | continue; | 1256 | continue; |
| 1168 | } | 1257 | } |
| 1169 | 1258 | ||
| 1170 | dprintk(3, "buffer for plane %d changed\n", plane); | 1259 | dprintk(q, 3, "buffer for plane %d changed\n", plane); |
| 1171 | 1260 | ||
| 1172 | if (!reacquired) { | 1261 | if (!reacquired) { |
| 1173 | reacquired = true; | 1262 | reacquired = true; |
| @@ -1187,7 +1276,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) · 13 unmodified lines | |||
| 1187 | q->alloc_devs[plane] ? : q->dev, | 1276 | q->alloc_devs[plane] ? : q->dev, |
| 1188 | dbuf, planes[plane].length, q->dma_dir); | 1277 | dbuf, planes[plane].length, q->dma_dir); |
| 1189 | if (IS_ERR(mem_priv)) { | 1278 | if (IS_ERR(mem_priv)) { |
| 1190 | dprintk(1, "failed to attach dmabuf\n"); | 1279 | dprintk(q, 1, "failed to attach dmabuf\n"); |
| 1191 | ret = PTR_ERR(mem_priv); | 1280 | ret = PTR_ERR(mem_priv); |
| 1192 | dma_buf_put(dbuf); | 1281 | dma_buf_put(dbuf); |
| 1193 | goto err; | 1282 | goto err; |
| @@ -1208,7 +1297,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) · 14 unmodified lines | |||
| 1208 | 1297 | ||
| 1209 | ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); | 1298 | ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); |
| 1210 | if (ret) { | 1299 | if (ret) { |
| 1211 | dprintk(1, "failed to map dmabuf for plane %d\n", | 1300 | dprintk(q, 1, "failed to map dmabuf for plane %d\n", |
| 1212 | plane); | 1301 | plane); |
| 1213 | goto err; | 1302 | goto err; |
| 1214 | } | 1303 | } |
| @@ -1233,14 +1322,14 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) · 18 unmodified lines | |||
| 1233 | */ | 1322 | */ |
| 1234 | ret = call_vb_qop(vb, buf_init, vb); | 1323 | ret = call_vb_qop(vb, buf_init, vb); |
| 1235 | if (ret) { | 1324 | if (ret) { |
| 1236 | dprintk(1, "buffer initialization failed\n"); | 1325 | dprintk(q, 1, "buffer initialization failed\n"); |
| 1237 | goto err; | 1326 | goto err; |
| 1238 | } | 1327 | } |
| 1239 | } | 1328 | } |
| 1240 | 1329 | ||
| 1241 | ret = call_vb_qop(vb, buf_prepare, vb); | 1330 | ret = call_vb_qop(vb, buf_prepare, vb); |
| 1242 | if (ret) { | 1331 | if (ret) { |
| 1243 | dprintk(1, "buffer preparation failed\n"); | 1332 | dprintk(q, 1, "buffer preparation failed\n"); |
| 1244 | call_void_vb_qop(vb, buf_cleanup, vb); | 1333 | call_void_vb_qop(vb, buf_cleanup, vb); |
| 1245 | goto err; | 1334 | goto err; |
| 1246 | } | 1335 | } |
| @@ -1272,11 +1361,10 @@ static int __buf_prepare(struct vb2_buffer *vb) · 25 unmodified lines | |||
| 1272 | { | 1361 | { |
| 1273 | struct vb2_queue *q = vb->vb2_queue; | 1362 | struct vb2_queue *q = vb->vb2_queue; |
| 1274 | enum vb2_buffer_state orig_state = vb->state; | 1363 | enum vb2_buffer_state orig_state = vb->state; |
| 1275 | unsigned int plane; | ||
| 1276 | int ret; | 1364 | int ret; |
| 1277 | 1365 | ||
| 1278 | if (q->error) { | 1366 | if (q->error) { |
| 1279 | dprintk(1, "fatal error occurred on queue\n"); | 1367 | dprintk(q, 1, "fatal error occurred on queue\n"); |
| 1280 | return -EIO; | 1368 | return -EIO; |
| 1281 | } | 1369 | } |
| 1282 | 1370 | ||
| @@ -1287,7 +1375,7 @@ static int __buf_prepare(struct vb2_buffer *vb) · 4 unmodified lines | |||
| 1287 | if (q->is_output) { | 1375 | if (q->is_output) { |
| 1288 | ret = call_vb_qop(vb, buf_out_validate, vb); | 1376 | ret = call_vb_qop(vb, buf_out_validate, vb); |
| 1289 | if (ret) { | 1377 | if (ret) { |
| 1290 | dprintk(1, "buffer validation failed\n"); | 1378 | dprintk(q, 1, "buffer validation failed\n"); |
| 1291 | return ret; | 1379 | return ret; |
| 1292 | } | 1380 | } |
| 1293 | } | 1381 | } |
| @@ -1311,16 +1399,12 @@ static int __buf_prepare(struct vb2_buffer *vb) · 17 unmodified lines | |||
| 1311 | } | 1399 | } |
| 1312 | 1400 | ||
| 1313 | if (ret) { | 1401 | if (ret) { |
| 1314 | dprintk(1, "buffer preparation failed: %d\n", ret); | 1402 | dprintk(q, 1, "buffer preparation failed: %d\n", ret); |
| 1315 | vb->state = orig_state; | 1403 | vb->state = orig_state; |
| 1316 | return ret; | 1404 | return ret; |
| 1317 | } | 1405 | } |
| 1318 | 1406 | ||
| 1319 | /* sync buffers */ | 1407 | __vb2_buf_mem_prepare(vb); |
| 1320 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
| 1321 | call_void_memop(vb, prepare, vb->planes[plane].mem_priv); | ||
| 1322 | |||
| 1323 | vb->synced = 1; | ||
| 1324 | vb->prepared = 1; | 1408 | vb->prepared = 1; |
| 1325 | vb->state = orig_state; | 1409 | vb->state = orig_state; |
| 1326 | 1410 | ||
| @@ -1423,12 +1507,12 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) · 96 unmodified lines | |||
| 1423 | 1507 | ||
| 1424 | vb = q->bufs[index]; | 1508 | vb = q->bufs[index]; |
| 1425 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | 1509 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { |
| 1426 | dprintk(1, "invalid buffer state %d\n", | 1510 | dprintk(q, 1, "invalid buffer state %s\n", |
| 1427 | vb->state); | 1511 | vb2_state_name(vb->state)); |
| 1428 | return -EINVAL; | 1512 | return -EINVAL; |
| 1429 | } | 1513 | } |
| 1430 | if (vb->prepared) { | 1514 | if (vb->prepared) { |
| 1431 | dprintk(1, "buffer already prepared\n"); | 1515 | dprintk(q, 1, "buffer already prepared\n"); |
| 1432 | return -EINVAL; | 1516 | return -EINVAL; |
| 1433 | } | 1517 | } |
| 1434 | 1518 | ||
| @@ -1439,7 +1523,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) · 4 unmodified lines | |||
| 1439 | /* Fill buffer information for the userspace */ | 1523 | /* Fill buffer information for the userspace */ |
| 1440 | call_void_bufop(q, fill_user_buffer, vb, pb); | 1524 | call_void_bufop(q, fill_user_buffer, vb, pb); |
| 1441 | 1525 | ||
| 1442 | dprintk(2, "prepare of buffer %d succeeded\n", vb->index); | 1526 | dprintk(q, 2, "prepare of buffer %d succeeded\n", vb->index); |
| 1443 | 1527 | ||
| 1444 | return 0; | 1528 | return 0; |
| 1445 | } | 1529 | } |
| @@ -1477,7 +1561,7 @@ static int vb2_start_streaming(struct vb2_queue *q) · 31 unmodified lines | |||
| 1477 | 1561 | ||
| 1478 | q->start_streaming_called = 0; | 1562 | q->start_streaming_called = 0; |
| 1479 | 1563 | ||
| 1480 | dprintk(1, "driver refused to start streaming\n"); | 1564 | dprintk(q, 1, "driver refused to start streaming\n"); |
| 1481 | /* | 1565 | /* |
| 1482 | * If you see this warning, then the driver isn't cleaning up properly | 1566 | * If you see this warning, then the driver isn't cleaning up properly |
| 1483 | * after a failed start_streaming(). See the start_streaming() | 1567 | * after a failed start_streaming(). See the start_streaming() |
| @@ -1515,7 +1599,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, · 31 unmodified lines | |||
| 1515 | int ret; | 1599 | int ret; |
| 1516 | 1600 | ||
| 1517 | if (q->error) { | 1601 | if (q->error) { |
| 1518 | dprintk(1, "fatal error occurred on queue\n"); | 1602 | dprintk(q, 1, "fatal error occurred on queue\n"); |
| 1519 | return -EIO; | 1603 | return -EIO; |
| 1520 | } | 1604 | } |
| 1521 | 1605 | ||
| @@ -1523,14 +1607,14 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, · 1 unmodified line | |||
| 1523 | 1607 | ||
| 1524 | if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && | 1608 | if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && |
| 1525 | q->requires_requests) { | 1609 | q->requires_requests) { |
| 1526 | dprintk(1, "qbuf requires a request\n"); | 1610 | dprintk(q, 1, "qbuf requires a request\n"); |
| 1527 | return -EBADR; | 1611 | return -EBADR; |
| 1528 | } | 1612 | } |
| 1529 | 1613 | ||
| 1530 | if ((req && q->uses_qbuf) || | 1614 | if ((req && q->uses_qbuf) || |
| 1531 | (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && | 1615 | (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && |
| 1532 | q->uses_requests)) { | 1616 | q->uses_requests)) { |
| 1533 | dprintk(1, "queue in wrong mode (qbuf vs requests)\n"); | 1617 | dprintk(q, 1, "queue in wrong mode (qbuf vs requests)\n"); |
| 1534 | return -EBUSY; | 1618 | return -EBUSY; |
| 1535 | } | 1619 | } |
| 1536 | 1620 | ||
| @@ -1539,7 +1623,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, · 2 unmodified lines | |||
| 1539 | 1623 | ||
| 1540 | q->uses_requests = 1; | 1624 | q->uses_requests = 1; |
| 1541 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | 1625 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { |
| 1542 | dprintk(1, "buffer %d not in dequeued state\n", | 1626 | dprintk(q, 1, "buffer %d not in dequeued state\n", |
| 1543 | vb->index); | 1627 | vb->index); |
| 1544 | return -EINVAL; | 1628 | return -EINVAL; |
| 1545 | } | 1629 | } |
| @@ -1547,7 +1631,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, · 1 unmodified line | |||
| 1547 | if (q->is_output && !vb->prepared) { | 1631 | if (q->is_output && !vb->prepared) { |
| 1548 | ret = call_vb_qop(vb, buf_out_validate, vb); | 1632 | ret = call_vb_qop(vb, buf_out_validate, vb); |
| 1549 | if (ret) { | 1633 | if (ret) { |
| 1550 | dprintk(1, "buffer validation failed\n"); | 1634 | dprintk(q, 1, "buffer validation failed\n"); |
| 1551 | return ret; | 1635 | return ret; |
| 1552 | } | 1636 | } |
| 1553 | } | 1637 | } |
| @@ -1583,7 +1667,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, · 29 unmodified lines | |||
| 1583 | call_void_bufop(q, fill_user_buffer, vb, pb); | 1667 | call_void_bufop(q, fill_user_buffer, vb, pb); |
| 1584 | } | 1668 | } |
| 1585 | 1669 | ||
| 1586 | dprintk(2, "qbuf of buffer %d succeeded\n", vb->index); | 1670 | dprintk(q, 2, "qbuf of buffer %d succeeded\n", vb->index); |
| 1587 | return 0; | 1671 | return 0; |
| 1588 | } | 1672 | } |
| 1589 | 1673 | ||
| @@ -1600,10 +1684,11 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, · 10 unmodified lines | |||
| 1600 | } | 1684 | } |
| 1601 | break; | 1685 | break; |
| 1602 | case VB2_BUF_STATE_PREPARING: | 1686 | case VB2_BUF_STATE_PREPARING: |
| 1603 | dprintk(1, "buffer still being prepared\n"); | 1687 | dprintk(q, 1, "buffer still being prepared\n"); |
| 1604 | return -EINVAL; | 1688 | return -EINVAL; |
| 1605 | default: | 1689 | default: |
| 1606 | dprintk(1, "invalid buffer state %d\n", vb->state); | 1690 | dprintk(q, 1, "invalid buffer state %s\n", |
| 1691 | vb2_state_name(vb->state)); | ||
| 1607 | return -EINVAL; | 1692 | return -EINVAL; |
| 1608 | } | 1693 | } |
| 1609 | 1694 | ||
| @@ -1645,7 +1730,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, · 35 unmodified lines | |||
| 1645 | return ret; | 1730 | return ret; |
| 1646 | } | 1731 | } |
| 1647 | 1732 | ||
| 1648 | dprintk(2, "qbuf of buffer %d succeeded\n", vb->index); | 1733 | dprintk(q, 2, "qbuf of buffer %d succeeded\n", vb->index); |
| 1649 | return 0; | 1734 | return 0; |
| 1650 | } | 1735 | } |
| 1651 | EXPORT_SYMBOL_GPL(vb2_core_qbuf); | 1736 | EXPORT_SYMBOL_GPL(vb2_core_qbuf); |
| @@ -1671,22 +1756,22 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) · 19 unmodified lines | |||
| 1671 | int ret; | 1756 | int ret; |
| 1672 | 1757 | ||
| 1673 | if (q->waiting_in_dqbuf) { | 1758 | if (q->waiting_in_dqbuf) { |
| 1674 | dprintk(1, "another dup()ped fd is waiting for a buffer\n"); | 1759 | dprintk(q, 1, "another dup()ped fd is waiting for a buffer\n"); |
| 1675 | return -EBUSY; | 1760 | return -EBUSY; |
| 1676 | } | 1761 | } |
| 1677 | 1762 | ||
| 1678 | if (!q->streaming) { | 1763 | if (!q->streaming) { |
| 1679 | dprintk(1, "streaming off, will not wait for buffers\n"); | 1764 | dprintk(q, 1, "streaming off, will not wait for buffers\n"); |
| 1680 | return -EINVAL; | 1765 | return -EINVAL; |
| 1681 | } | 1766 | } |
| 1682 | 1767 | ||
| 1683 | if (q->error) { | 1768 | if (q->error) { |
| 1684 | dprintk(1, "Queue in error state, will not wait for buffers\n"); | 1769 | dprintk(q, 1, "Queue in error state, will not wait for buffers\n"); |
| 1685 | return -EIO; | 1770 | return -EIO; |
| 1686 | } | 1771 | } |
| 1687 | 1772 | ||
| 1688 | if (q->last_buffer_dequeued) { | 1773 | if (q->last_buffer_dequeued) { |
| 1689 | dprintk(3, "last buffer dequeued already, will not wait for buffers\n"); | 1774 | dprintk(q, 3, "last buffer dequeued already, will not wait for buffers\n"); |
| 1690 | return -EPIPE; | 1775 | return -EPIPE; |
| 1691 | } | 1776 | } |
| 1692 | 1777 | ||
| @@ -1698,7 +1783,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) · 5 unmodified lines | |||
| 1698 | } | 1783 | } |
| 1699 | 1784 | ||
| 1700 | if (nonblocking) { | 1785 | if (nonblocking) { |
| 1701 | dprintk(3, "nonblocking and no buffers to dequeue, will not wait\n"); | 1786 | dprintk(q, 3, "nonblocking and no buffers to dequeue, will not wait\n"); |
| 1702 | return -EAGAIN; | 1787 | return -EAGAIN; |
| 1703 | } | 1788 | } |
| 1704 | 1789 | ||
| @@ -1713,7 +1798,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) · 8 unmodified lines | |||
| 1713 | /* | 1798 | /* |
| 1714 | * All locks have been released, it is safe to sleep now. | 1799 | * All locks have been released, it is safe to sleep now. |
| 1715 | */ | 1800 | */ |
| 1716 | dprintk(3, "will sleep waiting for buffers\n"); | 1801 | dprintk(q, 3, "will sleep waiting for buffers\n"); |
| 1717 | ret = wait_event_interruptible(q->done_wq, | 1802 | ret = wait_event_interruptible(q->done_wq, |
| 1718 | !list_empty(&q->done_list) || !q->streaming || | 1803 | !list_empty(&q->done_list) || !q->streaming || |
| 1719 | q->error); | 1804 | q->error); |
| @@ -1725,7 +1810,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) · 5 unmodified lines | |||
| 1725 | call_void_qop(q, wait_finish, q); | 1810 | call_void_qop(q, wait_finish, q); |
| 1726 | q->waiting_in_dqbuf = 0; | 1811 | q->waiting_in_dqbuf = 0; |
| 1727 | if (ret) { | 1812 | if (ret) { |
| 1728 | dprintk(1, "sleep was interrupted\n"); | 1813 | dprintk(q, 1, "sleep was interrupted\n"); |
| 1729 | return ret; | 1814 | return ret; |
| 1730 | } | 1815 | } |
| 1731 | } | 1816 | } |
| @@ -1773,7 +1858,7 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, · 41 unmodified lines | |||
| 1773 | int vb2_wait_for_all_buffers(struct vb2_queue *q) | 1858 | int vb2_wait_for_all_buffers(struct vb2_queue *q) |
| 1774 | { | 1859 | { |
| 1775 | if (!q->streaming) { | 1860 | if (!q->streaming) { |
| 1776 | dprintk(1, "streaming off, will not wait for buffers\n"); | 1861 | dprintk(q, 1, "streaming off, will not wait for buffers\n"); |
| 1777 | return -EINVAL; | 1862 | return -EINVAL; |
| 1778 | } | 1863 | } |
| 1779 | 1864 | ||
| @@ -1811,13 +1896,14 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, · 31 unmodified lines | |||
| 1811 | 1896 | ||
| 1812 | switch (vb->state) { | 1897 | switch (vb->state) { |
| 1813 | case VB2_BUF_STATE_DONE: | 1898 | case VB2_BUF_STATE_DONE: |
| 1814 | dprintk(3, "returning done buffer\n"); | 1899 | dprintk(q, 3, "returning done buffer\n"); |
| 1815 | break; | 1900 | break; |
| 1816 | case VB2_BUF_STATE_ERROR: | 1901 | case VB2_BUF_STATE_ERROR: |
| 1817 | dprintk(3, "returning done buffer with errors\n"); | 1902 | dprintk(q, 3, "returning done buffer with errors\n"); |
| 1818 | break; | 1903 | break; |
| 1819 | default: | 1904 | default: |
| 1820 | dprintk(1, "invalid buffer state\n"); | 1905 | dprintk(q, 1, "invalid buffer state %s\n", |
| 1906 | vb2_state_name(vb->state)); | ||
| 1821 | return -EINVAL; | 1907 | return -EINVAL; |
| 1822 | } | 1908 | } |
| 1823 | 1909 | ||
| @@ -1848,8 +1934,8 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, · 24 unmodified lines | |||
| 1848 | media_request_put(vb->request); | 1934 | media_request_put(vb->request); |
| 1849 | vb->request = NULL; | 1935 | vb->request = NULL; |
| 1850 | 1936 | ||
| 1851 | dprintk(2, "dqbuf of buffer %d, with state %d\n", | 1937 | dprintk(q, 2, "dqbuf of buffer %d, state: %s\n", |
| 1852 | vb->index, vb->state); | 1938 | vb->index, vb2_state_name(vb->state)); |
| 1853 | 1939 | ||
| 1854 | return 0; | 1940 | return 0; |
| 1855 | 1941 | ||
| @@ -1940,14 +2026,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) · 84 unmodified lines | |||
| 1940 | call_void_vb_qop(vb, buf_request_complete, vb); | 2026 | call_void_vb_qop(vb, buf_request_complete, vb); |
| 1941 | } | 2027 | } |
| 1942 | 2028 | ||
| 1943 | if (vb->synced) { | 2029 | __vb2_buf_mem_finish(vb); |
| 1944 | unsigned int plane; | ||
| 1945 | |||
| 1946 | for (plane = 0; plane < vb->num_planes; ++plane) | ||
| 1947 | call_void_memop(vb, finish, | ||
| 1948 | vb->planes[plane].mem_priv); | ||
| 1949 | vb->synced = 0; | ||
| 1950 | } | ||
| 1951 | 2030 | ||
| 1952 | if (vb->prepared) { | 2031 | if (vb->prepared) { |
| 1953 | call_void_vb_qop(vb, buf_finish, vb); | 2032 | call_void_vb_qop(vb, buf_finish, vb); |
| @@ -1971,22 +2050,22 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) · 17 unmodified lines | |||
| 1971 | int ret; | 2050 | int ret; |
| 1972 | 2051 | ||
| 1973 | if (type != q->type) { | 2052 | if (type != q->type) { |
| 1974 | dprintk(1, "invalid stream type\n"); | 2053 | dprintk(q, 1, "invalid stream type\n"); |
| 1975 | return -EINVAL; | 2054 | return -EINVAL; |
| 1976 | } | 2055 | } |
| 1977 | 2056 | ||
| 1978 | if (q->streaming) { | 2057 | if (q->streaming) { |
| 1979 | dprintk(3, "already streaming\n"); | 2058 | dprintk(q, 3, "already streaming\n"); |
| 1980 | return 0; | 2059 | return 0; |
| 1981 | } | 2060 | } |
| 1982 | 2061 | ||
| 1983 | if (!q->num_buffers) { | 2062 | if (!q->num_buffers) { |
| 1984 | dprintk(1, "no buffers have been allocated\n"); | 2063 | dprintk(q, 1, "no buffers have been allocated\n"); |
| 1985 | return -EINVAL; | 2064 | return -EINVAL; |
| 1986 | } | 2065 | } |
| 1987 | 2066 | ||
| 1988 | if (q->num_buffers < q->min_buffers_needed) { | 2067 | if (q->num_buffers < q->min_buffers_needed) { |
| 1989 | dprintk(1, "need at least %u allocated buffers\n", | 2068 | dprintk(q, 1, "need at least %u allocated buffers\n", |
| 1990 | q->min_buffers_needed); | 2069 | q->min_buffers_needed); |
| 1991 | return -EINVAL; | 2070 | return -EINVAL; |
| 1992 | } | 2071 | } |
| @@ -2006,7 +2085,7 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) · 13 unmodified lines | |||
| 2006 | 2085 | ||
| 2007 | q->streaming = 1; | 2086 | q->streaming = 1; |
| 2008 | 2087 | ||
| 2009 | dprintk(3, "successful\n"); | 2088 | dprintk(q, 3, "successful\n"); |
| 2010 | return 0; | 2089 | return 0; |
| 2011 | } | 2090 | } |
| 2012 | EXPORT_SYMBOL_GPL(vb2_core_streamon); | 2091 | EXPORT_SYMBOL_GPL(vb2_core_streamon); |
| @@ -2022,7 +2101,7 @@ EXPORT_SYMBOL_GPL(vb2_queue_error); · 9 unmodified lines | |||
| 2022 | int vb2_core_streamoff(struct vb2_queue *q, unsigned int type) | 2101 | int vb2_core_streamoff(struct vb2_queue *q, unsigned int type) |
| 2023 | { | 2102 | { |
| 2024 | if (type != q->type) { | 2103 | if (type != q->type) { |
| 2025 | dprintk(1, "invalid stream type\n"); | 2104 | dprintk(q, 1, "invalid stream type\n"); |
| 2026 | return -EINVAL; | 2105 | return -EINVAL; |
| 2027 | } | 2106 | } |
| 2028 | 2107 | ||
| @@ -2039,7 +2118,7 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type) · 10 unmodified lines | |||
| 2039 | q->waiting_for_buffers = !q->is_output; | 2118 | q->waiting_for_buffers = !q->is_output; |
| 2040 | q->last_buffer_dequeued = false; | 2119 | q->last_buffer_dequeued = false; |
| 2041 | 2120 | ||
| 2042 | dprintk(3, "successful\n"); | 2121 | dprintk(q, 3, "successful\n"); |
| 2043 | return 0; | 2122 | return 0; |
| 2044 | } | 2123 | } |
| 2045 | EXPORT_SYMBOL_GPL(vb2_core_streamoff); | 2124 | EXPORT_SYMBOL_GPL(vb2_core_streamoff); |
| @@ -2082,39 +2161,39 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, · 36 unmodified lines | |||
| 2082 | struct dma_buf *dbuf; | 2161 | struct dma_buf *dbuf; |
| 2083 | 2162 | ||
| 2084 | if (q->memory != VB2_MEMORY_MMAP) { | 2163 | if (q->memory != VB2_MEMORY_MMAP) { |
| 2085 | dprintk(1, "queue is not currently set up for mmap\n"); | 2164 | dprintk(q, 1, "queue is not currently set up for mmap\n"); |
| 2086 | return -EINVAL; | 2165 | return -EINVAL; |
| 2087 | } | 2166 | } |
| 2088 | 2167 | ||
| 2089 | if (!q->mem_ops->get_dmabuf) { | 2168 | if (!q->mem_ops->get_dmabuf) { |
| 2090 | dprintk(1, "queue does not support DMA buffer exporting\n"); | 2169 | dprintk(q, 1, "queue does not support DMA buffer exporting\n"); |
| 2091 | return -EINVAL; | 2170 | return -EINVAL; |
| 2092 | } | 2171 | } |
| 2093 | 2172 | ||
| 2094 | if (flags & ~(O_CLOEXEC | O_ACCMODE)) { | 2173 | if (flags & ~(O_CLOEXEC | O_ACCMODE)) { |
| 2095 | dprintk(1, "queue does support only O_CLOEXEC and access mode flags\n"); | 2174 | dprintk(q, 1, "queue does support only O_CLOEXEC and access mode flags\n"); |
| 2096 | return -EINVAL; | 2175 | return -EINVAL; |
| 2097 | } | 2176 | } |
| 2098 | 2177 | ||
| 2099 | if (type != q->type) { | 2178 | if (type != q->type) { |
| 2100 | dprintk(1, "invalid buffer type\n"); | 2179 | dprintk(q, 1, "invalid buffer type\n"); |
| 2101 | return -EINVAL; | 2180 | return -EINVAL; |
| 2102 | } | 2181 | } |
| 2103 | 2182 | ||
| 2104 | if (index >= q->num_buffers) { | 2183 | if (index >= q->num_buffers) { |
| 2105 | dprintk(1, "buffer index out of range\n"); | 2184 | dprintk(q, 1, "buffer index out of range\n"); |
| 2106 | return -EINVAL; | 2185 | return -EINVAL; |
| 2107 | } | 2186 | } |
| 2108 | 2187 | ||
| 2109 | vb = q->bufs[index]; | 2188 | vb = q->bufs[index]; |
| 2110 | 2189 | ||
| 2111 | if (plane >= vb->num_planes) { | 2190 | if (plane >= vb->num_planes) { |
| 2112 | dprintk(1, "buffer plane out of range\n"); | 2191 | dprintk(q, 1, "buffer plane out of range\n"); |
| 2113 | return -EINVAL; | 2192 | return -EINVAL; |
| 2114 | } | 2193 | } |
| 2115 | 2194 | ||
| 2116 | if (vb2_fileio_is_active(q)) { | 2195 | if (vb2_fileio_is_active(q)) { |
| 2117 | dprintk(1, "expbuf: file io in progress\n"); | 2196 | dprintk(q, 1, "expbuf: file io in progress\n"); |
| 2118 | return -EBUSY; | 2197 | return -EBUSY; |
| 2119 | } | 2198 | } |
| 2120 | 2199 | ||
| @@ -2123,20 +2202,20 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type, · 2 unmodified lines | |||
| 2123 | dbuf = call_ptr_memop(vb, get_dmabuf, vb_plane->mem_priv, | 2202 | dbuf = call_ptr_memop(vb, get_dmabuf, vb_plane->mem_priv, |
| 2124 | flags & O_ACCMODE); | 2203 | flags & O_ACCMODE); |
| 2125 | if (IS_ERR_OR_NULL(dbuf)) { | 2204 | if (IS_ERR_OR_NULL(dbuf)) { |
| 2126 | dprintk(1, "failed to export buffer %d, plane %d\n", | 2205 | dprintk(q, 1, "failed to export buffer %d, plane %d\n", |
| 2127 | index, plane); | 2206 | index, plane); |
| 2128 | return -EINVAL; | 2207 | return -EINVAL; |
| 2129 | } | 2208 | } |
| 2130 | 2209 | ||
| 2131 | ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE); | 2210 | ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE); |
| 2132 | if (ret < 0) { | 2211 | if (ret < 0) { |
| 2133 | dprintk(3, "buffer %d, plane %d failed to export (%d)\n", | 2212 | dprintk(q, 3, "buffer %d, plane %d failed to export (%d)\n", |
| 2134 | index, plane, ret); | 2213 | index, plane, ret); |
| 2135 | dma_buf_put(dbuf); | 2214 | dma_buf_put(dbuf); |
| 2136 | return ret; | 2215 | return ret; |
| 2137 | } | 2216 | } |
| 2138 | 2217 | ||
| 2139 | dprintk(3, "buffer %d, plane %d exported as %d descriptor\n", | 2218 | dprintk(q, 3, "buffer %d, plane %d exported as %d descriptor\n", |
| 2140 | index, plane, ret); | 2219 | index, plane, ret); |
| 2141 | *fd = ret; | 2220 | *fd = ret; |
| 2142 | 2221 | ||
| @@ -2153,7 +2232,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) · 10 unmodified lines | |||
| 2153 | unsigned long length; | 2232 | unsigned long length; |
| 2154 | 2233 | ||
| 2155 | if (q->memory != VB2_MEMORY_MMAP) { | 2234 | if (q->memory != VB2_MEMORY_MMAP) { |
| 2156 | dprintk(1, "queue is not currently set up for mmap\n"); | 2235 | dprintk(q, 1, "queue is not currently set up for mmap\n"); |
| 2157 | return -EINVAL; | 2236 | return -EINVAL; |
| 2158 | } | 2237 | } |
| 2159 | 2238 | ||
| @@ -2161,17 +2240,17 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) · 1 unmodified line | |||
| 2161 | * Check memory area access mode. | 2240 | * Check memory area access mode. |
| 2162 | */ | 2241 | */ |
| 2163 | if (!(vma->vm_flags & VM_SHARED)) { | 2242 | if (!(vma->vm_flags & VM_SHARED)) { |
| 2164 | dprintk(1, "invalid vma flags, VM_SHARED needed\n"); | 2243 | dprintk(q, 1, "invalid vma flags, VM_SHARED needed\n"); |
| 2165 | return -EINVAL; | 2244 | return -EINVAL; |
| 2166 | } | 2245 | } |
| 2167 | if (q->is_output) { | 2246 | if (q->is_output) { |
| 2168 | if (!(vma->vm_flags & VM_WRITE)) { | 2247 | if (!(vma->vm_flags & VM_WRITE)) { |
| 2169 | dprintk(1, "invalid vma flags, VM_WRITE needed\n"); | 2248 | dprintk(q, 1, "invalid vma flags, VM_WRITE needed\n"); |
| 2170 | return -EINVAL; | 2249 | return -EINVAL; |
| 2171 | } | 2250 | } |
| 2172 | } else { | 2251 | } else { |
| 2173 | if (!(vma->vm_flags & VM_READ)) { | 2252 | if (!(vma->vm_flags & VM_READ)) { |
| 2174 | dprintk(1, "invalid vma flags, VM_READ needed\n"); | 2253 | dprintk(q, 1, "invalid vma flags, VM_READ needed\n"); |
| 2175 | return -EINVAL; | 2254 | return -EINVAL; |
| 2176 | } | 2255 | } |
| 2177 | } | 2256 | } |
| @@ -2179,7 +2258,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) · 1 unmodified line | |||
| 2179 | mutex_lock(&q->mmap_lock); | 2258 | mutex_lock(&q->mmap_lock); |
| 2180 | 2259 | ||
| 2181 | if (vb2_fileio_is_active(q)) { | 2260 | if (vb2_fileio_is_active(q)) { |
| 2182 | dprintk(1, "mmap: file io in progress\n"); | 2261 | dprintk(q, 1, "mmap: file io in progress\n"); |
| 2183 | ret = -EBUSY; | 2262 | ret = -EBUSY; |
| 2184 | goto unlock; | 2263 | goto unlock; |
| 2185 | } | 2264 | } |
| @@ -2200,7 +2279,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) · 14 unmodified lines | |||
| 2200 | */ | 2279 | */ |
| 2201 | length = PAGE_ALIGN(vb->planes[plane].length); | 2280 | length = PAGE_ALIGN(vb->planes[plane].length); |
| 2202 | if (length < (vma->vm_end - vma->vm_start)) { | 2281 | if (length < (vma->vm_end - vma->vm_start)) { |
| 2203 | dprintk(1, | 2282 | dprintk(q, 1, |
| 2204 | "MMAP invalid, as it would overflow buffer length\n"); | 2283 | "MMAP invalid, as it would overflow buffer length\n"); |
| 2205 | ret = -EINVAL; | 2284 | ret = -EINVAL; |
| 2206 | goto unlock; | 2285 | goto unlock; |
| @@ -2220,7 +2299,7 @@ unlock: · 13 unmodified lines | |||
| 2220 | if (ret) | 2299 | if (ret) |
| 2221 | return ret; | 2300 | return ret; |
| 2222 | 2301 | ||
| 2223 | dprintk(3, "buffer %d, plane %d successfully mapped\n", buffer, plane); | 2302 | dprintk(q, 3, "buffer %d, plane %d successfully mapped\n", buffer, plane); |
| 2224 | return 0; | 2303 | return 0; |
| 2225 | } | 2304 | } |
| 2226 | EXPORT_SYMBOL_GPL(vb2_mmap); | 2305 | EXPORT_SYMBOL_GPL(vb2_mmap); |
| @@ -2239,7 +2318,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, · 12 unmodified lines | |||
| 2239 | int ret; | 2318 | int ret; |
| 2240 | 2319 | ||
| 2241 | if (q->memory != VB2_MEMORY_MMAP) { | 2320 | if (q->memory != VB2_MEMORY_MMAP) { |
| 2242 | dprintk(1, "queue is not currently set up for mmap\n"); | 2321 | dprintk(q, 1, "queue is not currently set up for mmap\n"); |
| 2243 | return -EINVAL; | 2322 | return -EINVAL; |
| 2244 | } | 2323 | } |
| 2245 | 2324 | ||
| @@ -2291,6 +2370,10 @@ int vb2_core_queue_init(struct vb2_queue *q) · 45 unmodified lines | |||
| 2291 | else | 2370 | else |
| 2292 | q->dma_dir = q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 2371 | q->dma_dir = q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
| 2293 | 2372 | ||
| 2373 | if (q->name[0] == '\0') | ||
| 2374 | snprintf(q->name, sizeof(q->name), "%s-%p", | ||
| 2375 | q->is_output ? "out" : "cap", q); | ||
| 2376 | |||
| 2294 | return 0; | 2377 | return 0; |
| 2295 | } | 2378 | } |
| 2296 | EXPORT_SYMBOL_GPL(vb2_core_queue_init); | 2379 | EXPORT_SYMBOL_GPL(vb2_core_queue_init); |
| @@ -2479,7 +2562,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) · 182 unmodified lines | |||
| 2479 | */ | 2562 | */ |
| 2480 | count = 1; | 2563 | count = 1; |
| 2481 | 2564 | ||
| 2482 | dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", | 2565 | dprintk(q, 3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", |
| 2483 | (read) ? "read" : "write", count, q->fileio_read_once, | 2566 | (read) ? "read" : "write", count, q->fileio_read_once, |
| 2484 | q->fileio_write_immediately); | 2567 | q->fileio_write_immediately); |
| 2485 | 2568 | ||
| @@ -2498,7 +2581,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) · 12 unmodified lines | |||
| 2498 | fileio->memory = VB2_MEMORY_MMAP; | 2581 | fileio->memory = VB2_MEMORY_MMAP; |
| 2499 | fileio->type = q->type; | 2582 | fileio->type = q->type; |
| 2500 | q->fileio = fileio; | 2583 | q->fileio = fileio; |
| 2501 | ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count); | 2584 | ret = vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count); |
| 2502 | if (ret) | 2585 | if (ret) |
| 2503 | goto err_kfree; | 2586 | goto err_kfree; |
| 2504 | 2587 | ||
| @@ -2555,7 +2638,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) · 50 unmodified lines | |||
| 2555 | 2638 | ||
| 2556 | err_reqbufs: | 2639 | err_reqbufs: |
| 2557 | fileio->count = 0; | 2640 | fileio->count = 0; |
| 2558 | vb2_core_reqbufs(q, fileio->memory, &fileio->count); | 2641 | vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count); |
| 2559 | 2642 | ||
| 2560 | err_kfree: | 2643 | err_kfree: |
| 2561 | q->fileio = NULL; | 2644 | q->fileio = NULL; |
| @@ -2575,9 +2658,9 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q) · 13 unmodified lines | |||
| 2575 | vb2_core_streamoff(q, q->type); | 2658 | vb2_core_streamoff(q, q->type); |
| 2576 | q->fileio = NULL; | 2659 | q->fileio = NULL; |
| 2577 | fileio->count = 0; | 2660 | fileio->count = 0; |
| 2578 | vb2_core_reqbufs(q, fileio->memory, &fileio->count); | 2661 | vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count); |
| 2579 | kfree(fileio); | 2662 | kfree(fileio); |
| 2580 | dprintk(3, "file io emulator closed\n"); | 2663 | dprintk(q, 3, "file io emulator closed\n"); |
| 2581 | } | 2664 | } |
| 2582 | return 0; | 2665 | return 0; |
| 2583 | } | 2666 | } |
| @@ -2606,7 +2689,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ · 22 unmodified lines | |||
| 2606 | unsigned index; | 2689 | unsigned index; |
| 2607 | int ret; | 2690 | int ret; |
| 2608 | 2691 | ||
| 2609 | dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n", | 2692 | dprintk(q, 3, "mode %s, offset %ld, count %zd, %sblocking\n", |
| 2610 | read ? "read" : "write", (long)*ppos, count, | 2693 | read ? "read" : "write", (long)*ppos, count, |
| 2611 | nonblock ? "non" : ""); | 2694 | nonblock ? "non" : ""); |
| 2612 | 2695 | ||
| @@ -2614,7 +2697,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ · 1 unmodified line | |||
| 2614 | return -EINVAL; | 2697 | return -EINVAL; |
| 2615 | 2698 | ||
| 2616 | if (q->waiting_in_dqbuf) { | 2699 | if (q->waiting_in_dqbuf) { |
| 2617 | dprintk(3, "another dup()ped fd is %s\n", | 2700 | dprintk(q, 3, "another dup()ped fd is %s\n", |
| 2618 | read ? "reading" : "writing"); | 2701 | read ? "reading" : "writing"); |
| 2619 | return -EBUSY; | 2702 | return -EBUSY; |
| 2620 | } | 2703 | } |
| @@ -2624,7 +2707,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ · 3 unmodified lines | |||
| 2624 | */ | 2707 | */ |
| 2625 | if (!vb2_fileio_is_active(q)) { | 2708 | if (!vb2_fileio_is_active(q)) { |
| 2626 | ret = __vb2_init_fileio(q, read); | 2709 | ret = __vb2_init_fileio(q, read); |
| 2627 | dprintk(3, "vb2_init_fileio result: %d\n", ret); | 2710 | dprintk(q, 3, "vb2_init_fileio result: %d\n", ret); |
| 2628 | if (ret) | 2711 | if (ret) |
| 2629 | return ret; | 2712 | return ret; |
| 2630 | } | 2713 | } |
| @@ -2641,7 +2724,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ · 10 unmodified lines | |||
| 2641 | * Call vb2_dqbuf to get buffer back. | 2724 | * Call vb2_dqbuf to get buffer back. |
| 2642 | */ | 2725 | */ |
| 2643 | ret = vb2_core_dqbuf(q, &index, NULL, nonblock); | 2726 | ret = vb2_core_dqbuf(q, &index, NULL, nonblock); |
| 2644 | dprintk(5, "vb2_dqbuf result: %d\n", ret); | 2727 | dprintk(q, 5, "vb2_dqbuf result: %d\n", ret); |
| 2645 | if (ret) | 2728 | if (ret) |
| 2646 | return ret; | 2729 | return ret; |
| 2647 | fileio->dq_count += 1; | 2730 | fileio->dq_count += 1; |
| @@ -2672,20 +2755,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ · 24 unmodified lines | |||
| 2672 | */ | 2755 | */ |
| 2673 | if (buf->pos + count > buf->size) { | 2756 | if (buf->pos + count > buf->size) { |
| 2674 | count = buf->size - buf->pos; | 2757 | count = buf->size - buf->pos; |
| 2675 | dprintk(5, "reducing read count: %zd\n", count); | 2758 | dprintk(q, 5, "reducing read count: %zd\n", count); |
| 2676 | } | 2759 | } |
| 2677 | 2760 | ||
| 2678 | /* | 2761 | /* |
| 2679 | * Transfer data to userspace. | 2762 | * Transfer data to userspace. |
| 2680 | */ | 2763 | */ |
| 2681 | dprintk(3, "copying %zd bytes - buffer %d, offset %u\n", | 2764 | dprintk(q, 3, "copying %zd bytes - buffer %d, offset %u\n", |
| 2682 | count, index, buf->pos); | 2765 | count, index, buf->pos); |
| 2683 | if (read) | 2766 | if (read) |
| 2684 | ret = copy_to_user(data, buf->vaddr + buf->pos, count); | 2767 | ret = copy_to_user(data, buf->vaddr + buf->pos, count); |
| 2685 | else | 2768 | else |
| 2686 | ret = copy_from_user(buf->vaddr + buf->pos, data, count); | 2769 | ret = copy_from_user(buf->vaddr + buf->pos, data, count); |
| 2687 | if (ret) { | 2770 | if (ret) { |
| 2688 | dprintk(3, "error copying data\n"); | 2771 | dprintk(q, 3, "error copying data\n"); |
| 2689 | return -EFAULT; | 2772 | return -EFAULT; |
| 2690 | } | 2773 | } |
| 2691 | 2774 | ||
| @@ -2705,7 +2788,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ · 13 unmodified lines | |||
| 2705 | * Check if this is the last buffer to read. | 2788 | * Check if this is the last buffer to read. |
| 2706 | */ | 2789 | */ |
| 2707 | if (read && fileio->read_once && fileio->dq_count == 1) { | 2790 | if (read && fileio->read_once && fileio->dq_count == 1) { |
| 2708 | dprintk(3, "read limit reached\n"); | 2791 | dprintk(q, 3, "read limit reached\n"); |
| 2709 | return __vb2_cleanup_fileio(q); | 2792 | return __vb2_cleanup_fileio(q); |
| 2710 | } | 2793 | } |
| 2711 | 2794 | ||
| @@ -2717,7 +2800,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ · 5 unmodified lines | |||
| 2717 | if (copy_timestamp) | 2800 | if (copy_timestamp) |
| 2718 | b->timestamp = ktime_get_ns(); | 2801 | b->timestamp = ktime_get_ns(); |
| 2719 | ret = vb2_core_qbuf(q, index, NULL, NULL); | 2802 | ret = vb2_core_qbuf(q, index, NULL, NULL); |
| 2720 | dprintk(5, "vb2_dbuf result: %d\n", ret); | 2803 | dprintk(q, 5, "vb2_dbuf result: %d\n", ret); |
| 2721 | if (ret) | 2804 | if (ret) |
| 2722 | return ret; | 2805 | return ret; |
| 2723 | 2806 | ||
| @@ -2804,7 +2887,7 @@ static int vb2_thread(void *data) · 80 unmodified lines | |||
| 2804 | if (!threadio->stop) | 2887 | if (!threadio->stop) |
| 2805 | ret = vb2_core_dqbuf(q, &index, NULL, 0); | 2888 | ret = vb2_core_dqbuf(q, &index, NULL, 0); |
| 2806 | call_void_qop(q, wait_prepare, q); | 2889 | call_void_qop(q, wait_prepare, q); |
| 2807 | dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); | 2890 | dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret); |
| 2808 | if (!ret) | 2891 | if (!ret) |
| 2809 | vb = q->bufs[index]; | 2892 | vb = q->bufs[index]; |
| 2810 | } | 2893 | } |
| @@ -2858,7 +2941,7 @@ int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv, · 47 unmodified lines | |||
| 2858 | threadio->priv = priv; | 2941 | threadio->priv = priv; |
| 2859 | 2942 | ||
| 2860 | ret = __vb2_init_fileio(q, !q->is_output); | 2943 | ret = __vb2_init_fileio(q, !q->is_output); |
| 2861 | dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); | 2944 | dprintk(q, 3, "file io: vb2_init_fileio result: %d\n", ret); |
| 2862 | if (ret) | 2945 | if (ret) |
| 2863 | goto nomem; | 2946 | goto nomem; |
| 2864 | q->threadio = threadio; | 2947 | q->threadio = threadio; |
| @@ -42,6 +42,11 @@ struct vb2_dc_buf { · 41 unmodified lines | |||
| 42 | struct dma_buf_attachment *db_attach; | 42 | struct dma_buf_attachment *db_attach; |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | static inline bool vb2_dc_buffer_consistent(unsigned long attr) | ||
| 46 | { | ||
| 47 | return !(attr & DMA_ATTR_NON_CONSISTENT); | ||
| 48 | } | ||
| 49 | |||
| 45 | /*********************************************/ | 50 | /*********************************************/ |
| 46 | /* scatterlist table functions */ | 51 | /* scatterlist table functions */ |
| 47 | /*********************************************/ | 52 | /*********************************************/ |
| @@ -95,8 +100,7 @@ static void vb2_dc_prepare(void *buf_priv) · 47 unmodified lines | |||
| 95 | struct vb2_dc_buf *buf = buf_priv; | 100 | struct vb2_dc_buf *buf = buf_priv; |
| 96 | struct sg_table *sgt = buf->dma_sgt; | 101 | struct sg_table *sgt = buf->dma_sgt; |
| 97 | 102 | ||
| 98 | /* DMABUF exporter will flush the cache for us */ | 103 | if (!sgt) |
| 99 | if (!sgt || buf->db_attach) | ||
| 100 | return; | 104 | return; |
| 101 | 105 | ||
| 102 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, | 106 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, |
| @@ -108,8 +112,7 @@ static void vb2_dc_finish(void *buf_priv) · 5 unmodified lines | |||
| 108 | struct vb2_dc_buf *buf = buf_priv; | 112 | struct vb2_dc_buf *buf = buf_priv; |
| 109 | struct sg_table *sgt = buf->dma_sgt; | 113 | struct sg_table *sgt = buf->dma_sgt; |
| 110 | 114 | ||
| 111 | /* DMABUF exporter will flush the cache for us */ | 115 | if (!sgt) |
| 112 | if (!sgt || buf->db_attach) | ||
| 113 | return; | 116 | return; |
| 114 | 117 | ||
| 115 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); | 118 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); |
| @@ -149,8 +152,7 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs, · 33 unmodified lines | |||
| 149 | if (!buf) | 152 | if (!buf) |
| 150 | return ERR_PTR(-ENOMEM); | 153 | return ERR_PTR(-ENOMEM); |
| 151 | 154 | ||
| 152 | if (attrs) | 155 | buf->attrs = attrs; |
| 153 | buf->attrs = attrs; | ||
| 154 | buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, | 156 | buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, |
| 155 | GFP_KERNEL | gfp_flags, buf->attrs); | 157 | GFP_KERNEL | gfp_flags, buf->attrs); |
| 156 | if (!buf->cookie) { | 158 | if (!buf->cookie) { |
| @@ -335,6 +337,34 @@ static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf) · 178 unmodified lines | |||
| 335 | vb2_dc_put(dbuf->priv); | 337 | vb2_dc_put(dbuf->priv); |
| 336 | } | 338 | } |
| 337 | 339 | ||
| 340 | static int | ||
| 341 | vb2_dc_dmabuf_ops_begin_cpu_access(struct dma_buf *dbuf, | ||
| 342 | enum dma_data_direction direction) | ||
| 343 | { | ||
| 344 | struct vb2_dc_buf *buf = dbuf->priv; | ||
| 345 | struct sg_table *sgt = buf->dma_sgt; | ||
| 346 | |||
| 347 | if (vb2_dc_buffer_consistent(buf->attrs)) | ||
| 348 | return 0; | ||
| 349 | |||
| 350 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); | ||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static int | ||
| 355 | vb2_dc_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf, | ||
| 356 | enum dma_data_direction direction) | ||
| 357 | { | ||
| 358 | struct vb2_dc_buf *buf = dbuf->priv; | ||
| 359 | struct sg_table *sgt = buf->dma_sgt; | ||
| 360 | |||
| 361 | if (vb2_dc_buffer_consistent(buf->attrs)) | ||
| 362 | return 0; | ||
| 363 | |||
| 364 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 338 | static void *vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf) | 368 | static void *vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf) |
| 339 | { | 369 | { |
| 340 | struct vb2_dc_buf *buf = dbuf->priv; | 370 | struct vb2_dc_buf *buf = dbuf->priv; |
| @@ -353,6 +383,8 @@ static const struct dma_buf_ops vb2_dc_dmabuf_ops = { · 12 unmodified lines | |||
| 353 | .detach = vb2_dc_dmabuf_ops_detach, | 383 | .detach = vb2_dc_dmabuf_ops_detach, |
| 354 | .map_dma_buf = vb2_dc_dmabuf_ops_map, | 384 | .map_dma_buf = vb2_dc_dmabuf_ops_map, |
| 355 | .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap, | 385 | .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap, |
| 386 | .begin_cpu_access = vb2_dc_dmabuf_ops_begin_cpu_access, | ||
| 387 | .end_cpu_access = vb2_dc_dmabuf_ops_end_cpu_access, | ||
| 356 | .vmap = vb2_dc_dmabuf_ops_vmap, | 388 | .vmap = vb2_dc_dmabuf_ops_vmap, |
| 357 | .mmap = vb2_dc_dmabuf_ops_mmap, | 389 | .mmap = vb2_dc_dmabuf_ops_mmap, |
| 358 | .release = vb2_dc_dmabuf_ops_release, | 390 | .release = vb2_dc_dmabuf_ops_release, |
| @@ -120,6 +120,12 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, · 119 unmodified lines | |||
| 120 | buf->num_pages = size >> PAGE_SHIFT; | 120 | buf->num_pages = size >> PAGE_SHIFT; |
| 121 | buf->dma_sgt = &buf->sg_table; | 121 | buf->dma_sgt = &buf->sg_table; |
| 122 | 122 | ||
| 123 | /* | ||
| 124 | * NOTE: dma-sg allocates memory using the page allocator directly, so | ||
| 125 | * there is no memory consistency guarantee, hence dma-sg ignores DMA | ||
| 126 | * attributes passed from the upper layer. That means that | ||
| 127 | * V4L2_FLAG_MEMORY_NON_CONSISTENT has no effect on dma-sg buffers. | ||
| 128 | */ | ||
| 123 | buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *), | 129 | buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *), |
| 124 | GFP_KERNEL | __GFP_ZERO); | 130 | GFP_KERNEL | __GFP_ZERO); |
| 125 | if (!buf->pages) | 131 | if (!buf->pages) |
| @@ -198,10 +204,6 @@ static void vb2_dma_sg_prepare(void *buf_priv) · 72 unmodified lines | |||
| 198 | struct vb2_dma_sg_buf *buf = buf_priv; | 204 | struct vb2_dma_sg_buf *buf = buf_priv; |
| 199 | struct sg_table *sgt = buf->dma_sgt; | 205 | struct sg_table *sgt = buf->dma_sgt; |
| 200 | 206 | ||
| 201 | /* DMABUF exporter will flush the cache for us */ | ||
| 202 | if (buf->db_attach) | ||
| 203 | return; | ||
| 204 | |||
| 205 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, | 207 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents, |
| 206 | buf->dma_dir); | 208 | buf->dma_dir); |
| 207 | } | 209 | } |
| @@ -211,10 +213,6 @@ static void vb2_dma_sg_finish(void *buf_priv) · 3 unmodified lines | |||
| 211 | struct vb2_dma_sg_buf *buf = buf_priv; | 213 | struct vb2_dma_sg_buf *buf = buf_priv; |
| 212 | struct sg_table *sgt = buf->dma_sgt; | 214 | struct sg_table *sgt = buf->dma_sgt; |
| 213 | 215 | ||
| 214 | /* DMABUF exporter will flush the cache for us */ | ||
| 215 | if (buf->db_attach) | ||
| 216 | return; | ||
| 217 | |||
| 218 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); | 216 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); |
| 219 | } | 217 | } |
| 220 | 218 | ||
| @@ -469,6 +467,28 @@ static void vb2_dma_sg_dmabuf_ops_release(struct dma_buf *dbuf) · 248 unmodified lines | |||
| 469 | vb2_dma_sg_put(dbuf->priv); | 467 | vb2_dma_sg_put(dbuf->priv); |
| 470 | } | 468 | } |
| 471 | 469 | ||
| 470 | static int | ||
| 471 | vb2_dma_sg_dmabuf_ops_begin_cpu_access(struct dma_buf *dbuf, | ||
| 472 | enum dma_data_direction direction) | ||
| 473 | { | ||
| 474 | struct vb2_dma_sg_buf *buf = dbuf->priv; | ||
| 475 | struct sg_table *sgt = buf->dma_sgt; | ||
| 476 | |||
| 477 | dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); | ||
| 478 | return 0; | ||
| 479 | } | ||
| 480 | |||
| 481 | static int | ||
| 482 | vb2_dma_sg_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf, | ||
| 483 | enum dma_data_direction direction) | ||
| 484 | { | ||
| 485 | struct vb2_dma_sg_buf *buf = dbuf->priv; | ||
| 486 | struct sg_table *sgt = buf->dma_sgt; | ||
| 487 | |||
| 488 | dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); | ||
| 489 | return 0; | ||
| 490 | } | ||
| 491 | |||
| 472 | static void *vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf) | 492 | static void *vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf) |
| 473 | { | 493 | { |
| 474 | struct vb2_dma_sg_buf *buf = dbuf->priv; | 494 | struct vb2_dma_sg_buf *buf = dbuf->priv; |
| @@ -487,6 +507,8 @@ static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = { · 12 unmodified lines | |||
| 487 | .detach = vb2_dma_sg_dmabuf_ops_detach, | 507 | .detach = vb2_dma_sg_dmabuf_ops_detach, |
| 488 | .map_dma_buf = vb2_dma_sg_dmabuf_ops_map, | 508 | .map_dma_buf = vb2_dma_sg_dmabuf_ops_map, |
| 489 | .unmap_dma_buf = vb2_dma_sg_dmabuf_ops_unmap, | 509 | .unmap_dma_buf = vb2_dma_sg_dmabuf_ops_unmap, |
| 510 | .begin_cpu_access = vb2_dma_sg_dmabuf_ops_begin_cpu_access, | ||
| 511 | .end_cpu_access = vb2_dma_sg_dmabuf_ops_end_cpu_access, | ||
| 490 | .vmap = vb2_dma_sg_dmabuf_ops_vmap, | 512 | .vmap = vb2_dma_sg_dmabuf_ops_vmap, |
| 491 | .mmap = vb2_dma_sg_dmabuf_ops_mmap, | 513 | .mmap = vb2_dma_sg_dmabuf_ops_mmap, |
| 492 | .release = vb2_dma_sg_dmabuf_ops_release, | 514 | .release = vb2_dma_sg_dmabuf_ops_release, |
| @@ -35,10 +35,11 @@ · 34 unmodified lines | |||
| 35 | static int debug; | 35 | static int debug; |
| 36 | module_param(debug, int, 0644); | 36 | module_param(debug, int, 0644); |
| 37 | 37 | ||
| 38 | #define dprintk(level, fmt, arg...) \ | 38 | #define dprintk(q, level, fmt, arg...) \ |
| 39 | do { \ | 39 | do { \ |
| 40 | if (debug >= level) \ | 40 | if (debug >= level) \ |
| 41 | pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \ | 41 | pr_info("vb2-v4l2: [%p] %s: " fmt, \ |
| 42 | (q)->name, __func__, ## arg); \ | ||
| 42 | } while (0) | 43 | } while (0) |
| 43 | 44 | ||
| 44 | /* Flags that are set by us */ | 45 | /* Flags that are set by us */ |
| @@ -66,12 +67,14 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer · 21 unmodified lines | |||
| 66 | 67 | ||
| 67 | /* Is memory for copying plane information present? */ | 68 | /* Is memory for copying plane information present? */ |
| 68 | if (b->m.planes == NULL) { | 69 | if (b->m.planes == NULL) { |
| 69 | dprintk(1, "multi-planar buffer passed but planes array not provided\n"); | 70 | dprintk(vb->vb2_queue, 1, |
| 71 | "multi-planar buffer passed but planes array not provided\n"); | ||
| 70 | return -EINVAL; | 72 | return -EINVAL; |
| 71 | } | 73 | } |
| 72 | 74 | ||
| 73 | if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) { | 75 | if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) { |
| 74 | dprintk(1, "incorrect planes array length, expected %d, got %d\n", | 76 | dprintk(vb->vb2_queue, 1, |
| 77 | "incorrect planes array length, expected %d, got %d\n", | ||
| 75 | vb->num_planes, b->length); | 78 | vb->num_planes, b->length); |
| 76 | return -EINVAL; | 79 | return -EINVAL; |
| 77 | } | 80 | } |
| @@ -94,7 +97,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) · 16 unmodified lines | |||
| 94 | unsigned int bytesused; | 97 | unsigned int bytesused; |
| 95 | unsigned int plane; | 98 | unsigned int plane; |
| 96 | 99 | ||
| 97 | if (!V4L2_TYPE_IS_OUTPUT(b->type)) | 100 | if (V4L2_TYPE_IS_CAPTURE(b->type)) |
| 98 | return 0; | 101 | return 0; |
| 99 | 102 | ||
| 100 | if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { | 103 | if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { |
| @@ -114,7 +117,8 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) · 13 unmodified lines | |||
| 114 | return -EINVAL; | 117 | return -EINVAL; |
| 115 | } | 118 | } |
| 116 | } else { | 119 | } else { |
| 117 | length = (b->memory == VB2_MEMORY_USERPTR) | 120 | length = (b->memory == VB2_MEMORY_USERPTR || |
| 121 | b->memory == VB2_MEMORY_DMABUF) | ||
| 118 | ? b->length : vb->planes[0].length; | 122 | ? b->length : vb->planes[0].length; |
| 119 | 123 | ||
| 120 | if (b->bytesused > length) | 124 | if (b->bytesused > length) |
| @@ -179,7 +183,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b · 58 unmodified lines | |||
| 179 | 183 | ||
| 180 | ret = __verify_length(vb, b); | 184 | ret = __verify_length(vb, b); |
| 181 | if (ret < 0) { | 185 | if (ret < 0) { |
| 182 | dprintk(1, "plane parameters verification failed: %d\n", ret); | 186 | dprintk(q, 1, "plane parameters verification failed: %d\n", ret); |
| 183 | return ret; | 187 | return ret; |
| 184 | } | 188 | } |
| 185 | if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) { | 189 | if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) { |
| @@ -192,7 +196,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b · 6 unmodified lines | |||
| 192 | * that just says that it is either a top or a bottom field, | 196 | * that just says that it is either a top or a bottom field, |
| 193 | * but not which of the two it is. | 197 | * but not which of the two it is. |
| 194 | */ | 198 | */ |
| 195 | dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n"); | 199 | dprintk(q, 1, "the field is incorrectly set to ALTERNATE for an output buffer\n"); |
| 196 | return -EINVAL; | 200 | return -EINVAL; |
| 197 | } | 201 | } |
| 198 | vbuf->sequence = 0; | 202 | vbuf->sequence = 0; |
| @@ -307,7 +311,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b · 108 unmodified lines | |||
| 307 | 311 | ||
| 308 | /* Zero flags that we handle */ | 312 | /* Zero flags that we handle */ |
| 309 | vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; | 313 | vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; |
| 310 | if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) { | 314 | if (!vb->vb2_queue->copy_timestamp || V4L2_TYPE_IS_CAPTURE(b->type)) { |
| 311 | /* | 315 | /* |
| 312 | * Non-COPY timestamps and non-OUTPUT queues will get | 316 | * Non-COPY timestamps and non-OUTPUT queues will get |
| 313 | * their timestamp and timestamp source flags from the | 317 | * their timestamp and timestamp source flags from the |
| @@ -337,6 +341,53 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b · 23 unmodified lines | |||
| 337 | return 0; | 341 | return 0; |
| 338 | } | 342 | } |
| 339 | 343 | ||
| 344 | static void set_buffer_cache_hints(struct vb2_queue *q, | ||
| 345 | struct vb2_buffer *vb, | ||
| 346 | struct v4l2_buffer *b) | ||
| 347 | { | ||
| 348 | /* | ||
| 349 | * DMA exporter should take care of cache syncs, so we can avoid | ||
| 350 | * explicit ->prepare()/->finish() syncs. For other ->memory types | ||
| 351 | * we always need ->prepare() or/and ->finish() cache sync. | ||
| 352 | */ | ||
| 353 | if (q->memory == VB2_MEMORY_DMABUF) { | ||
| 354 | vb->need_cache_sync_on_finish = 0; | ||
| 355 | vb->need_cache_sync_on_prepare = 0; | ||
| 356 | return; | ||
| 357 | } | ||
| 358 | |||
| 359 | /* | ||
| 360 | * Cache sync/invalidation flags are set by default in order to | ||
| 361 | * preserve existing behaviour for old apps/drivers. | ||
| 362 | */ | ||
| 363 | vb->need_cache_sync_on_prepare = 1; | ||
| 364 | vb->need_cache_sync_on_finish = 1; | ||
| 365 | |||
| 366 | if (!vb2_queue_allows_cache_hints(q)) { | ||
| 367 | /* | ||
| 368 | * Clear buffer cache flags if queue does not support user | ||
| 369 | * space hints. That's to indicate to userspace that these | ||
| 370 | * flags won't work. | ||
| 371 | */ | ||
| 372 | b->flags &= ~V4L2_BUF_FLAG_NO_CACHE_INVALIDATE; | ||
| 373 | b->flags &= ~V4L2_BUF_FLAG_NO_CACHE_CLEAN; | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* | ||
| 378 | * ->finish() cache sync can be avoided when queue direction is | ||
| 379 | * TO_DEVICE. | ||
| 380 | */ | ||
| 381 | if (q->dma_dir == DMA_TO_DEVICE) | ||
| 382 | vb->need_cache_sync_on_finish = 0; | ||
| 383 | |||
| 384 | if (b->flags & V4L2_BUF_FLAG_NO_CACHE_INVALIDATE) | ||
| 385 | vb->need_cache_sync_on_finish = 0; | ||
| 386 | |||
| 387 | if (b->flags & V4L2_BUF_FLAG_NO_CACHE_CLEAN) | ||
| 388 | vb->need_cache_sync_on_prepare = 0; | ||
| 389 | } | ||
| 390 | |||
| 340 | static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev, | 391 | static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev, |
| 341 | struct v4l2_buffer *b, bool is_prepare, | 392 | struct v4l2_buffer *b, bool is_prepare, |
| 342 | struct media_request **p_req) | 393 | struct media_request **p_req) |
| @@ -348,23 +399,23 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md · 5 unmodified lines | |||
| 348 | int ret; | 399 | int ret; |
| 349 | 400 | ||
| 350 | if (b->type != q->type) { | 401 | if (b->type != q->type) { |
| 351 | dprintk(1, "%s: invalid buffer type\n", opname); | 402 | dprintk(q, 1, "%s: invalid buffer type\n", opname); |
| 352 | return -EINVAL; | 403 | return -EINVAL; |
| 353 | } | 404 | } |
| 354 | 405 | ||
| 355 | if (b->index >= q->num_buffers) { | 406 | if (b->index >= q->num_buffers) { |
| 356 | dprintk(1, "%s: buffer index out of range\n", opname); | 407 | dprintk(q, 1, "%s: buffer index out of range\n", opname); |
| 357 | return -EINVAL; | 408 | return -EINVAL; |
| 358 | } | 409 | } |
| 359 | 410 | ||
| 360 | if (q->bufs[b->index] == NULL) { | 411 | if (q->bufs[b->index] == NULL) { |
| 361 | /* Should never happen */ | 412 | /* Should never happen */ |
| 362 | dprintk(1, "%s: buffer is NULL\n", opname); | 413 | dprintk(q, 1, "%s: buffer is NULL\n", opname); |
| 363 | return -EINVAL; | 414 | return -EINVAL; |
| 364 | } | 415 | } |
| 365 | 416 | ||
| 366 | if (b->memory != q->memory) { | 417 | if (b->memory != q->memory) { |
| 367 | dprintk(1, "%s: invalid memory type\n", opname); | 418 | dprintk(q, 1, "%s: invalid memory type\n", opname); |
| 368 | return -EINVAL; | 419 | return -EINVAL; |
| 369 | } | 420 | } |
| 370 | 421 | ||
| @@ -376,11 +427,12 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md · 5 unmodified lines | |||
| 376 | 427 | ||
| 377 | if (!is_prepare && (b->flags & V4L2_BUF_FLAG_REQUEST_FD) && | 428 | if (!is_prepare && (b->flags & V4L2_BUF_FLAG_REQUEST_FD) && |
| 378 | vb->state != VB2_BUF_STATE_DEQUEUED) { | 429 | vb->state != VB2_BUF_STATE_DEQUEUED) { |
| 379 | dprintk(1, "%s: buffer is not in dequeued state\n", opname); | 430 | dprintk(q, 1, "%s: buffer is not in dequeued state\n", opname); |
| 380 | return -EINVAL; | 431 | return -EINVAL; |
| 381 | } | 432 | } |
| 382 | 433 | ||
| 383 | if (!vb->prepared) { | 434 | if (!vb->prepared) { |
| 435 | set_buffer_cache_hints(q, vb, b); | ||
| 384 | /* Copy relevant information provided by the userspace */ | 436 | /* Copy relevant information provided by the userspace */ |
| 385 | memset(vbuf->planes, 0, | 437 | memset(vbuf->planes, 0, |
| 386 | sizeof(vbuf->planes[0]) * vb->num_planes); | 438 | sizeof(vbuf->planes[0]) * vb->num_planes); |
| @@ -394,19 +446,19 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md · 7 unmodified lines | |||
| 394 | 446 | ||
| 395 | if (!(b->flags & V4L2_BUF_FLAG_REQUEST_FD)) { | 447 | if (!(b->flags & V4L2_BUF_FLAG_REQUEST_FD)) { |
| 396 | if (q->requires_requests) { | 448 | if (q->requires_requests) { |
| 397 | dprintk(1, "%s: queue requires requests\n", opname); | 449 | dprintk(q, 1, "%s: queue requires requests\n", opname); |
| 398 | return -EBADR; | 450 | return -EBADR; |
| 399 | } | 451 | } |
| 400 | if (q->uses_requests) { | 452 | if (q->uses_requests) { |
| 401 | dprintk(1, "%s: queue uses requests\n", opname); | 453 | dprintk(q, 1, "%s: queue uses requests\n", opname); |
| 402 | return -EBUSY; | 454 | return -EBUSY; |
| 403 | } | 455 | } |
| 404 | return 0; | 456 | return 0; |
| 405 | } else if (!q->supports_requests) { | 457 | } else if (!q->supports_requests) { |
| 406 | dprintk(1, "%s: queue does not support requests\n", opname); | 458 | dprintk(q, 1, "%s: queue does not support requests\n", opname); |
| 407 | return -EBADR; | 459 | return -EBADR; |
| 408 | } else if (q->uses_qbuf) { | 460 | } else if (q->uses_qbuf) { |
| 409 | dprintk(1, "%s: queue does not use requests\n", opname); | 461 | dprintk(q, 1, "%s: queue does not use requests\n", opname); |
| 410 | return -EBUSY; | 462 | return -EBUSY; |
| 411 | } | 463 | } |
| 412 | 464 | ||
| @@ -436,13 +488,13 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md · 23 unmodified lines | |||
| 436 | return -EINVAL; | 488 | return -EINVAL; |
| 437 | 489 | ||
| 438 | if (b->request_fd < 0) { | 490 | if (b->request_fd < 0) { |
| 439 | dprintk(1, "%s: request_fd < 0\n", opname); | 491 | dprintk(q, 1, "%s: request_fd < 0\n", opname); |
| 440 | return -EINVAL; | 492 | return -EINVAL; |
| 441 | } | 493 | } |
| 442 | 494 | ||
| 443 | req = media_request_get_by_fd(mdev, b->request_fd); | 495 | req = media_request_get_by_fd(mdev, b->request_fd); |
| 444 | if (IS_ERR(req)) { | 496 | if (IS_ERR(req)) { |
| 445 | dprintk(1, "%s: invalid request_fd\n", opname); | 497 | dprintk(q, 1, "%s: invalid request_fd\n", opname); |
| 446 | return PTR_ERR(req); | 498 | return PTR_ERR(req); |
| 447 | } | 499 | } |
| 448 | 500 | ||
| @@ -452,7 +504,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md · 3 unmodified lines | |||
| 452 | */ | 504 | */ |
| 453 | if (req->state != MEDIA_REQUEST_STATE_IDLE && | 505 | if (req->state != MEDIA_REQUEST_STATE_IDLE && |
| 454 | req->state != MEDIA_REQUEST_STATE_UPDATING) { | 506 | req->state != MEDIA_REQUEST_STATE_UPDATING) { |
| 455 | dprintk(1, "%s: request is not idle\n", opname); | 507 | dprintk(q, 1, "%s: request is not idle\n", opname); |
| 456 | media_request_put(req); | 508 | media_request_put(req); |
| 457 | return -EBUSY; | 509 | return -EBUSY; |
| 458 | } | 510 | } |
| @@ -635,12 +687,12 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) · 176 unmodified lines | |||
| 635 | int ret; | 687 | int ret; |
| 636 | 688 | ||
| 637 | if (b->type != q->type) { | 689 | if (b->type != q->type) { |
| 638 | dprintk(1, "wrong buffer type\n"); | 690 | dprintk(q, 1, "wrong buffer type\n"); |
| 639 | return -EINVAL; | 691 | return -EINVAL; |
| 640 | } | 692 | } |
| 641 | 693 | ||
| 642 | if (b->index >= q->num_buffers) { | 694 | if (b->index >= q->num_buffers) { |
| 643 | dprintk(1, "buffer index out of range\n"); | 695 | dprintk(q, 1, "buffer index out of range\n"); |
| 644 | return -EINVAL; | 696 | return -EINVAL; |
| 645 | } | 697 | } |
| 646 | vb = q->bufs[b->index]; | 698 | vb = q->bufs[b->index]; |
| @@ -662,18 +714,30 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps) · 15 unmodified lines | |||
| 662 | *caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF; | 714 | *caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF; |
| 663 | if (q->subsystem_flags & VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF) | 715 | if (q->subsystem_flags & VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF) |
| 664 | *caps |= V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF; | 716 | *caps |= V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF; |
| 717 | if (q->allow_cache_hints && q->io_modes & VB2_MMAP) | ||
| 718 | *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS; | ||
| 665 | #ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API | 719 | #ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API |
| 666 | if (q->supports_requests) | 720 | if (q->supports_requests) |
| 667 | *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS; | 721 | *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS; |
| 668 | #endif | 722 | #endif |
| 669 | } | 723 | } |
| 670 | 724 | ||
| 725 | static void clear_consistency_attr(struct vb2_queue *q, | ||
| 726 | int memory, | ||
| 727 | unsigned int *flags) | ||
| 728 | { | ||
| 729 | if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) | ||
| 730 | *flags &= ~V4L2_FLAG_MEMORY_NON_CONSISTENT; | ||
| 731 | } | ||
| 732 | |||
| 671 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | 733 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) |
| 672 | { | 734 | { |
| 673 | int ret = vb2_verify_memory_type(q, req->memory, req->type); | 735 | int ret = vb2_verify_memory_type(q, req->memory, req->type); |
| 674 | 736 | ||
| 675 | fill_buf_caps(q, &req->capabilities); | 737 | fill_buf_caps(q, &req->capabilities); |
| 676 | return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count); | 738 | clear_consistency_attr(q, req->memory, &req->flags); |
| 739 | return ret ? ret : vb2_core_reqbufs(q, req->memory, | ||
| 740 | req->flags, &req->count); | ||
| 677 | } | 741 | } |
| 678 | EXPORT_SYMBOL_GPL(vb2_reqbufs); | 742 | EXPORT_SYMBOL_GPL(vb2_reqbufs); |
| 679 | 743 | ||
| @@ -683,7 +747,7 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, · 3 unmodified lines | |||
| 683 | int ret; | 747 | int ret; |
| 684 | 748 | ||
| 685 | if (vb2_fileio_is_active(q)) { | 749 | if (vb2_fileio_is_active(q)) { |
| 686 | dprintk(1, "file io in progress\n"); | 750 | dprintk(q, 1, "file io in progress\n"); |
| 687 | return -EBUSY; | 751 | return -EBUSY; |
| 688 | } | 752 | } |
| 689 | 753 | ||
| @@ -705,6 +769,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) · 15 unmodified lines | |||
| 705 | unsigned i; | 769 | unsigned i; |
| 706 | 770 | ||
| 707 | fill_buf_caps(q, &create->capabilities); | 771 | fill_buf_caps(q, &create->capabilities); |
| 772 | clear_consistency_attr(q, create->memory, &create->flags); | ||
| 708 | create->index = q->num_buffers; | 773 | create->index = q->num_buffers; |
| 709 | if (create->count == 0) | 774 | if (create->count == 0) |
| 710 | return ret != -EBUSY ? ret : 0; | 775 | return ret != -EBUSY ? ret : 0; |
| @@ -748,7 +813,10 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) · 37 unmodified lines | |||
| 748 | if (requested_sizes[i] == 0) | 813 | if (requested_sizes[i] == 0) |
| 749 | return -EINVAL; | 814 | return -EINVAL; |
| 750 | return ret ? ret : vb2_core_create_bufs(q, create->memory, | 815 | return ret ? ret : vb2_core_create_bufs(q, create->memory, |
| 751 | &create->count, requested_planes, requested_sizes); | 816 | create->flags, |
| 817 | &create->count, | ||
| 818 | requested_planes, | ||
| 819 | requested_sizes); | ||
| 752 | } | 820 | } |
| 753 | EXPORT_SYMBOL_GPL(vb2_create_bufs); | 821 | EXPORT_SYMBOL_GPL(vb2_create_bufs); |
| 754 | 822 | ||
| @@ -759,7 +827,7 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, · 4 unmodified lines | |||
| 759 | int ret; | 827 | int ret; |
| 760 | 828 | ||
| 761 | if (vb2_fileio_is_active(q)) { | 829 | if (vb2_fileio_is_active(q)) { |
| 762 | dprintk(1, "file io in progress\n"); | 830 | dprintk(q, 1, "file io in progress\n"); |
| 763 | return -EBUSY; | 831 | return -EBUSY; |
| 764 | } | 832 | } |
| 765 | 833 | ||
| @@ -778,12 +846,12 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) · 12 unmodified lines | |||
| 778 | int ret; | 846 | int ret; |
| 779 | 847 | ||
| 780 | if (vb2_fileio_is_active(q)) { | 848 | if (vb2_fileio_is_active(q)) { |
| 781 | dprintk(1, "file io in progress\n"); | 849 | dprintk(q, 1, "file io in progress\n"); |
| 782 | return -EBUSY; | 850 | return -EBUSY; |
| 783 | } | 851 | } |
| 784 | 852 | ||
| 785 | if (b->type != q->type) { | 853 | if (b->type != q->type) { |
| 786 | dprintk(1, "invalid buffer type\n"); | 854 | dprintk(q, 1, "invalid buffer type\n"); |
| 787 | return -EINVAL; | 855 | return -EINVAL; |
| 788 | } | 856 | } |
| 789 | 857 | ||
| @@ -807,7 +875,7 @@ EXPORT_SYMBOL_GPL(vb2_dqbuf); · 17 unmodified lines | |||
| 807 | int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) | 875 | int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) |
| 808 | { | 876 | { |
| 809 | if (vb2_fileio_is_active(q)) { | 877 | if (vb2_fileio_is_active(q)) { |
| 810 | dprintk(1, "file io in progress\n"); | 878 | dprintk(q, 1, "file io in progress\n"); |
| 811 | return -EBUSY; | 879 | return -EBUSY; |
| 812 | } | 880 | } |
| 813 | return vb2_core_streamon(q, type); | 881 | return vb2_core_streamon(q, type); |
| @@ -817,7 +885,7 @@ EXPORT_SYMBOL_GPL(vb2_streamon); · 3 unmodified lines | |||
| 817 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) | 885 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) |
| 818 | { | 886 | { |
| 819 | if (vb2_fileio_is_active(q)) { | 887 | if (vb2_fileio_is_active(q)) { |
| 820 | dprintk(1, "file io in progress\n"); | 888 | dprintk(q, 1, "file io in progress\n"); |
| 821 | return -EBUSY; | 889 | return -EBUSY; |
| 822 | } | 890 | } |
| 823 | return vb2_core_streamoff(q, type); | 891 | return vb2_core_streamoff(q, type); |
| @@ -831,7 +899,7 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) · 7 unmodified lines | |||
| 831 | } | 899 | } |
| 832 | EXPORT_SYMBOL_GPL(vb2_expbuf); | 900 | EXPORT_SYMBOL_GPL(vb2_expbuf); |
| 833 | 901 | ||
| 834 | int vb2_queue_init(struct vb2_queue *q) | 902 | int vb2_queue_init_name(struct vb2_queue *q, const char *name) |
| 835 | { | 903 | { |
| 836 | /* | 904 | /* |
| 837 | * Sanity check | 905 | * Sanity check |
| @@ -867,8 +935,19 @@ int vb2_queue_init(struct vb2_queue *q) · 29 unmodified lines | |||
| 867 | */ | 935 | */ |
| 868 | q->quirk_poll_must_check_waiting_for_buffers = true; | 936 | q->quirk_poll_must_check_waiting_for_buffers = true; |
| 869 | 937 | ||
| 938 | if (name) | ||
| 939 | strscpy(q->name, name, sizeof(q->name)); | ||
| 940 | else | ||
| 941 | q->name[0] = '\0'; | ||
| 942 | |||
| 870 | return vb2_core_queue_init(q); | 943 | return vb2_core_queue_init(q); |
| 871 | } | 944 | } |
| 945 | EXPORT_SYMBOL_GPL(vb2_queue_init_name); | ||
| 946 | |||
| 947 | int vb2_queue_init(struct vb2_queue *q) | ||
| 948 | { | ||
| 949 | return vb2_queue_init_name(q, NULL); | ||
| 950 | } | ||
| 872 | EXPORT_SYMBOL_GPL(vb2_queue_init); | 951 | EXPORT_SYMBOL_GPL(vb2_queue_init); |
| 873 | 952 | ||
| 874 | void vb2_queue_release(struct vb2_queue *q) | 953 | void vb2_queue_release(struct vb2_queue *q) |
| @@ -919,11 +998,12 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv, · 44 unmodified lines | |||
| 919 | int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type); | 998 | int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type); |
| 920 | 999 | ||
| 921 | fill_buf_caps(vdev->queue, &p->capabilities); | 1000 | fill_buf_caps(vdev->queue, &p->capabilities); |
| 1001 | clear_consistency_attr(vdev->queue, p->memory, &p->flags); | ||
| 922 | if (res) | 1002 | if (res) |
| 923 | return res; | 1003 | return res; |
| 924 | if (vb2_queue_is_busy(vdev, file)) | 1004 | if (vb2_queue_is_busy(vdev, file)) |
| 925 | return -EBUSY; | 1005 | return -EBUSY; |
| 926 | res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count); | 1006 | res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count); |
| 927 | /* If count == 0, then the owner has released all buffers and he | 1007 | /* If count == 0, then the owner has released all buffers and he |
| 928 | is no longer owner of the queue. Otherwise we have a new owner. */ | 1008 | is no longer owner of the queue. Otherwise we have a new owner. */ |
| 929 | if (res == 0) | 1009 | if (res == 0) |
| @@ -941,6 +1021,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, · 11 unmodified lines | |||
| 941 | 1021 | ||
| 942 | p->index = vdev->queue->num_buffers; | 1022 | p->index = vdev->queue->num_buffers; |
| 943 | fill_buf_caps(vdev->queue, &p->capabilities); | 1023 | fill_buf_caps(vdev->queue, &p->capabilities); |
| 1024 | clear_consistency_attr(vdev->queue, p->memory, &p->flags); | ||
| 944 | /* | 1025 | /* |
| 945 | * If count == 0, then just check if memory and type are valid. | 1026 | * If count == 0, then just check if memory and type are valid. |
| 946 | * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0. | 1027 | * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0. |
| @@ -342,7 +342,7 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req) · 341 unmodified lines | |||
| 342 | 342 | ||
| 343 | ctx->buf_siz = req->size; | 343 | ctx->buf_siz = req->size; |
| 344 | ctx->buf_cnt = req->count; | 344 | ctx->buf_cnt = req->count; |
| 345 | ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, &req->count); | 345 | ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, 0, &req->count); |
| 346 | if (ret) { | 346 | if (ret) { |
| 347 | ctx->state = DVB_VB2_STATE_NONE; | 347 | ctx->state = DVB_VB2_STATE_NONE; |
| 348 | dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name, | 348 | dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name, |
| @@ -155,17 +155,6 @@ if (debug >= level) \ · 154 unmodified lines | |||
| 155 | printk(KERN_DEBUG KBUILD_MODNAME ": %s " fmt, __func__, ##arg); \ | 155 | printk(KERN_DEBUG KBUILD_MODNAME ": %s " fmt, __func__, ##arg); \ |
| 156 | } while (0) | 156 | } while (0) |
| 157 | 157 | ||
| 158 | |||
| 159 | static inline u32 MulDiv32(u32 a, u32 b, u32 c) | ||
| 160 | { | ||
| 161 | u64 tmp64; | ||
| 162 | |||
| 163 | tmp64 = (u64) a * (u64) b; | ||
| 164 | do_div(tmp64, c); | ||
| 165 | |||
| 166 | return (u32) tmp64; | ||
| 167 | } | ||
| 168 | |||
| 169 | static inline u32 Frac28a(u32 a, u32 c) | 158 | static inline u32 Frac28a(u32 a, u32 c) |
| 170 | { | 159 | { |
| 171 | int i = 0; | 160 | int i = 0; |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> | 5 | * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> |
| 6 | * | 6 | * |
| 7 | * GNU Radio plugin "gr-kernel" for device usage will be on: | 7 | * GNU Radio plugin "gr-kernel" for device usage will be on: |
| 8 | * http://git.linuxtv.org/anttip/gr-kernel.git | 8 | * https://git.linuxtv.org/anttip/gr-kernel.git |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include "rtl2832_sdr.h" | 11 | #include "rtl2832_sdr.h" |
| @@ -272,6 +272,8 @@ static int node_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) · 271 unmodified lines | |||
| 272 | 272 | ||
| 273 | name_len = fw_csr_string(unit->directory, CSR_MODEL, | 273 | name_len = fw_csr_string(unit->directory, CSR_MODEL, |
| 274 | name, sizeof(name)); | 274 | name, sizeof(name)); |
| 275 | if (name_len < 0) | ||
| 276 | return name_len; | ||
| 275 | for (i = ARRAY_SIZE(model_names); --i; ) | 277 | for (i = ARRAY_SIZE(model_names); --i; ) |
| 276 | if (strlen(model_names[i]) <= name_len && | 278 | if (strlen(model_names[i]) <= name_len && |
| 277 | strncmp(name, model_names[i], name_len) == 0) | 279 | strncmp(name, model_names[i], name_len) == 0) |
| @@ -464,6 +464,19 @@ config VIDEO_VPX3220 · 463 unmodified lines | |||
| 464 | To compile this driver as a module, choose M here: the | 464 | To compile this driver as a module, choose M here: the |
| 465 | module will be called vpx3220. | 465 | module will be called vpx3220. |
| 466 | 466 | ||
| 467 | config VIDEO_MAX9286 | ||
| 468 | tristate "Maxim MAX9286 GMSL deserializer support" | ||
| 469 | depends on I2C && I2C_MUX | ||
| 470 | depends on OF | ||
| 471 | select V4L2_FWNODE | ||
| 472 | select VIDEO_V4L2_SUBDEV_API | ||
| 473 | select MEDIA_CONTROLLER | ||
| 474 | help | ||
| 475 | This driver supports the Maxim MAX9286 GMSL deserializer. | ||
| 476 | |||
| 477 | To compile this driver as a module, choose M here: the | ||
| 478 | module will be called max9286. | ||
| 479 | |||
| 467 | comment "Video and audio decoders" | 480 | comment "Video and audio decoders" |
| 468 | 481 | ||
| 469 | config VIDEO_SAA717X | 482 | config VIDEO_SAA717X |
| @@ -860,6 +873,7 @@ config VIDEO_OV2685 · 390 unmodified lines | |||
| 860 | config VIDEO_OV2740 | 873 | config VIDEO_OV2740 |
| 861 | tristate "OmniVision OV2740 sensor support" | 874 | tristate "OmniVision OV2740 sensor support" |
| 862 | depends on VIDEO_V4L2 && I2C | 875 | depends on VIDEO_V4L2 && I2C |
| 876 | depends on ACPI || COMPILE_TEST | ||
| 863 | select MEDIA_CONTROLLER | 877 | select MEDIA_CONTROLLER |
| 864 | select VIDEO_V4L2_SUBDEV_API | 878 | select VIDEO_V4L2_SUBDEV_API |
| 865 | select V4L2_FWNODE | 879 | select V4L2_FWNODE |
| @@ -1157,6 +1171,19 @@ config VIDEO_NOON010PC30 · 291 unmodified lines | |||
| 1157 | 1171 | ||
| 1158 | source "drivers/media/i2c/m5mols/Kconfig" | 1172 | source "drivers/media/i2c/m5mols/Kconfig" |
| 1159 | 1173 | ||
| 1174 | config VIDEO_RDACM20 | ||
| 1175 | tristate "IMI RDACM20 camera support" | ||
| 1176 | depends on I2C | ||
| 1177 | select V4L2_FWNODE | ||
| 1178 | select VIDEO_V4L2_SUBDEV_API | ||
| 1179 | select MEDIA_CONTROLLER | ||
| 1180 | help | ||
| 1181 | This driver supports the IMI RDACM20 GMSL camera, used in | ||
| 1182 | ADAS systems. | ||
| 1183 | |||
| 1184 | This camera should be used in conjunction with a GMSL | ||
| 1185 | deserialiser such as the MAX9286. | ||
| 1186 | |||
| 1160 | config VIDEO_RJ54N1 | 1187 | config VIDEO_RJ54N1 |
| 1161 | tristate "Sharp RJ54N1CB0C sensor support" | 1188 | tristate "Sharp RJ54N1CB0C sensor support" |
| 1162 | depends on I2C && VIDEO_V4L2 | 1189 | depends on I2C && VIDEO_V4L2 |
| @@ -1253,6 +1280,18 @@ config VIDEO_DW9714 · 90 unmodified lines | |||
| 1253 | capability. This is designed for linear control of | 1280 | capability. This is designed for linear control of |
| 1254 | voice coil motors, controlled via I2C serial interface. | 1281 | voice coil motors, controlled via I2C serial interface. |
| 1255 | 1282 | ||
| 1283 | config VIDEO_DW9768 | ||
| 1284 | tristate "DW9768 lens voice coil support" | ||
| 1285 | depends on I2C && VIDEO_V4L2 | ||
| 1286 | select MEDIA_CONTROLLER | ||
| 1287 | select VIDEO_V4L2_SUBDEV_API | ||
| 1288 | select V4L2_FWNODE | ||
| 1289 | help | ||
| 1290 | This is a driver for the DW9768 camera lens voice coil. | ||
| 1291 | DW9768 is a 10 bit DAC with 100mA output current sink | ||
| 1292 | capability. This is designed for linear control of | ||
| 1293 | voice coil motors, controlled via I2C serial interface. | ||
| 1294 | |||
| 1256 | config VIDEO_DW9807_VCM | 1295 | config VIDEO_DW9807_VCM |
| 1257 | tristate "DW9807 lens voice coil support" | 1296 | tristate "DW9807 lens voice coil support" |
| 1258 | depends on I2C && VIDEO_V4L2 | 1297 | depends on I2C && VIDEO_V4L2 |
| @@ -24,6 +24,7 @@ obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o · 23 unmodified lines | |||
| 24 | obj-$(CONFIG_VIDEO_AD5820) += ad5820.o | 24 | obj-$(CONFIG_VIDEO_AD5820) += ad5820.o |
| 25 | obj-$(CONFIG_VIDEO_AK7375) += ak7375.o | 25 | obj-$(CONFIG_VIDEO_AK7375) += ak7375.o |
| 26 | obj-$(CONFIG_VIDEO_DW9714) += dw9714.o | 26 | obj-$(CONFIG_VIDEO_DW9714) += dw9714.o |
| 27 | obj-$(CONFIG_VIDEO_DW9768) += dw9768.o | ||
| 27 | obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o | 28 | obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o |
| 28 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o | 29 | obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o |
| 29 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o | 30 | obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o |
| @@ -118,6 +119,9 @@ obj-$(CONFIG_VIDEO_IMX274) += imx274.o · 88 unmodified lines | |||
| 118 | obj-$(CONFIG_VIDEO_IMX290) += imx290.o | 119 | obj-$(CONFIG_VIDEO_IMX290) += imx290.o |
| 119 | obj-$(CONFIG_VIDEO_IMX319) += imx319.o | 120 | obj-$(CONFIG_VIDEO_IMX319) += imx319.o |
| 120 | obj-$(CONFIG_VIDEO_IMX355) += imx355.o | 121 | obj-$(CONFIG_VIDEO_IMX355) += imx355.o |
| 122 | obj-$(CONFIG_VIDEO_MAX9286) += max9286.o | ||
| 123 | rdacm20-camera_module-objs := rdacm20.o max9271.o | ||
| 124 | obj-$(CONFIG_VIDEO_RDACM20) += rdacm20-camera_module.o | ||
| 121 | obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o | 125 | obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o |
| 122 | 126 | ||
| 123 | obj-$(CONFIG_SDR_MAX2175) += max2175.o | 127 | obj-$(CONFIG_SDR_MAX2175) += max2175.o |
| @@ -0,0 +1,554 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // Copyright (c) 2020 MediaTek Inc. | ||
| 3 | |||
| 4 | #include <linux/delay.h> | ||
| 5 | #include <linux/i2c.h> | ||
| 6 | #include <linux/module.h> | ||
| 7 | #include <linux/pm_runtime.h> | ||
| 8 | #include <linux/regulator/consumer.h> | ||
| 9 | #include <media/v4l2-async.h> | ||
| 10 | #include <media/v4l2-ctrls.h> | ||
| 11 | #include <media/v4l2-device.h> | ||
| 12 | #include <media/v4l2-fwnode.h> | ||
| 13 | #include <media/v4l2-subdev.h> | ||
| 14 | |||
| 15 | #define DW9768_NAME "dw9768" | ||
| 16 | #define DW9768_MAX_FOCUS_POS (1024 - 1) | ||
| 17 | /* | ||
| 18 | * This sets the minimum granularity for the focus positions. | ||
| 19 | * A value of 1 gives maximum accuracy for a desired focus position | ||
| 20 | */ | ||
| 21 | #define DW9768_FOCUS_STEPS 1 | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Ring control and Power control register | ||
| 25 | * Bit[1] RING_EN | ||
| 26 | * 0: Direct mode | ||
| 27 | * 1: AAC mode (ringing control mode) | ||
| 28 | * Bit[0] PD | ||
| 29 | * 0: Normal operation mode | ||
| 30 | * 1: Power down mode | ||
| 31 | * DW9768 requires waiting time of Topr after PD reset takes place. | ||
| 32 | */ | ||
| 33 | #define DW9768_RING_PD_CONTROL_REG 0x02 | ||
| 34 | #define DW9768_PD_MODE_OFF 0x00 | ||
| 35 | #define DW9768_PD_MODE_EN BIT(0) | ||
| 36 | #define DW9768_AAC_MODE_EN BIT(1) | ||
| 37 | |||
| 38 | /* | ||
| 39 | * DW9768 separates two registers to control the VCM position. | ||
| 40 | * One for MSB value, another is LSB value. | ||
| 41 | * DAC_MSB: D[9:8] (ADD: 0x03) | ||
| 42 | * DAC_LSB: D[7:0] (ADD: 0x04) | ||
| 43 | * D[9:0] DAC data input: positive output current = D[9:0] / 1023 * 100[mA] | ||
| 44 | */ | ||
| 45 | #define DW9768_MSB_ADDR 0x03 | ||
| 46 | #define DW9768_LSB_ADDR 0x04 | ||
| 47 | #define DW9768_STATUS_ADDR 0x05 | ||
| 48 | |||
| 49 | /* | ||
| 50 | * AAC mode control & prescale register | ||
| 51 | * Bit[7:5] Namely AC[2:0], decide the VCM mode and operation time. | ||
| 52 | * 001 AAC2 0.48 x Tvib | ||
| 53 | * 010 AAC3 0.70 x Tvib | ||
| 54 | * 011 AAC4 0.75 x Tvib | ||
| 55 | * 101 AAC8 1.13 x Tvib | ||
| 56 | * Bit[2:0] Namely PRESC[2:0], set the internal clock dividing rate as follow. | ||
| 57 | * 000 2 | ||
| 58 | * 001 1 | ||
| 59 | * 010 1/2 | ||
| 60 | * 011 1/4 | ||
| 61 | * 100 8 | ||
| 62 | * 101 4 | ||
| 63 | */ | ||
| 64 | #define DW9768_AAC_PRESC_REG 0x06 | ||
| 65 | #define DW9768_AAC_MODE_SEL_MASK GENMASK(7, 5) | ||
| 66 | #define DW9768_CLOCK_PRE_SCALE_SEL_MASK GENMASK(2, 0) | ||
| 67 | |||
| 68 | /* | ||
| 69 | * VCM period of vibration register | ||
| 70 | * Bit[5:0] Defined as VCM rising periodic time (Tvib) together with PRESC[2:0] | ||
| 71 | * Tvib = (6.3ms + AACT[5:0] * 0.1ms) * Dividing Rate | ||
| 72 | * Dividing Rate is the internal clock dividing rate that is defined at | ||
| 73 | * PRESCALE register (ADD: 0x06) | ||
| 74 | */ | ||
| 75 | #define DW9768_AAC_TIME_REG 0x07 | ||
| 76 | |||
| 77 | /* | ||
| 78 | * DW9768 requires waiting time (delay time) of t_OPR after power-up, | ||
| 79 | * or in the case of PD reset taking place. | ||
| 80 | */ | ||
| 81 | #define DW9768_T_OPR_US 1000 | ||
| 82 | #define DW9768_TVIB_MS_BASE10 (64 - 1) | ||
| 83 | #define DW9768_AAC_MODE_DEFAULT 2 | ||
| 84 | #define DW9768_AAC_TIME_DEFAULT 0x20 | ||
| 85 | #define DW9768_CLOCK_PRE_SCALE_DEFAULT 1 | ||
| 86 | |||
| 87 | /* | ||
| 88 | * This acts as the minimum granularity of lens movement. | ||
| 89 | * Keep this value power of 2, so the control steps can be | ||
| 90 | * uniformly adjusted for gradual lens movement, with desired | ||
| 91 | * number of control steps. | ||
| 92 | */ | ||
| 93 | #define DW9768_MOVE_STEPS 16 | ||
| 94 | |||
| 95 | static const char * const dw9768_supply_names[] = { | ||
| 96 | "vin", /* Digital I/O power */ | ||
| 97 | "vdd", /* Digital core power */ | ||
| 98 | }; | ||
| 99 | |||
| 100 | /* dw9768 device structure */ | ||
| 101 | struct dw9768 { | ||
| 102 | struct regulator_bulk_data supplies[ARRAY_SIZE(dw9768_supply_names)]; | ||
| 103 | struct v4l2_ctrl_handler ctrls; | ||
| 104 | struct v4l2_ctrl *focus; | ||
| 105 | struct v4l2_subdev sd; | ||
| 106 | |||
| 107 | u32 aac_mode; | ||
| 108 | u32 aac_timing; | ||
| 109 | u32 clock_presc; | ||
| 110 | u32 move_delay_us; | ||
| 111 | }; | ||
| 112 | |||
| 113 | static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev) | ||
| 114 | { | ||
| 115 | return container_of(subdev, struct dw9768, sd); | ||
| 116 | } | ||
| 117 | |||
| 118 | struct regval_list { | ||
| 119 | u8 reg_num; | ||
| 120 | u8 value; | ||
| 121 | }; | ||
| 122 | |||
| 123 | struct dw9768_aac_mode_ot_multi { | ||
| 124 | u32 aac_mode_enum; | ||
| 125 | u32 ot_multi_base100; | ||
| 126 | }; | ||
| 127 | |||
| 128 | struct dw9768_clk_presc_dividing_rate { | ||
| 129 | u32 clk_presc_enum; | ||
| 130 | u32 dividing_rate_base100; | ||
| 131 | }; | ||
| 132 | |||
| 133 | static const struct dw9768_aac_mode_ot_multi aac_mode_ot_multi[] = { | ||
| 134 | {1, 48}, | ||
| 135 | {2, 70}, | ||
| 136 | {3, 75}, | ||
| 137 | {5, 113}, | ||
| 138 | }; | ||
| 139 | |||
| 140 | static const struct dw9768_clk_presc_dividing_rate presc_dividing_rate[] = { | ||
| 141 | {0, 200}, | ||
| 142 | {1, 100}, | ||
| 143 | {2, 50}, | ||
| 144 | {3, 25}, | ||
| 145 | {4, 800}, | ||
| 146 | {5, 400}, | ||
| 147 | }; | ||
| 148 | |||
| 149 | static u32 dw9768_find_ot_multi(u32 aac_mode_param) | ||
| 150 | { | ||
| 151 | u32 cur_ot_multi_base100 = 70; | ||
| 152 | unsigned int i; | ||
| 153 | |||
| 154 | for (i = 0; i < ARRAY_SIZE(aac_mode_ot_multi); i++) { | ||
| 155 | if (aac_mode_ot_multi[i].aac_mode_enum == aac_mode_param) { | ||
| 156 | cur_ot_multi_base100 = | ||
| 157 | aac_mode_ot_multi[i].ot_multi_base100; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | return cur_ot_multi_base100; | ||
| 162 | } | ||
| 163 | |||
| 164 | static u32 dw9768_find_dividing_rate(u32 presc_param) | ||
| 165 | { | ||
| 166 | u32 cur_clk_dividing_rate_base100 = 100; | ||
| 167 | unsigned int i; | ||
| 168 | |||
| 169 | for (i = 0; i < ARRAY_SIZE(presc_dividing_rate); i++) { | ||
| 170 | if (presc_dividing_rate[i].clk_presc_enum == presc_param) { | ||
| 171 | cur_clk_dividing_rate_base100 = | ||
| 172 | presc_dividing_rate[i].dividing_rate_base100; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | return cur_clk_dividing_rate_base100; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* | ||
| 180 | * DW9768_AAC_PRESC_REG & DW9768_AAC_TIME_REG determine VCM operation time. | ||
| 181 | * For current VCM mode: AAC3, Operation Time would be 0.70 x Tvib. | ||
| 182 | * Tvib = (6.3ms + AACT[5:0] * 0.1MS) * Dividing Rate. | ||
| 183 | * Below is calculation of the operation delay for each step. | ||
| 184 | */ | ||
| 185 | static inline u32 dw9768_cal_move_delay(u32 aac_mode_param, u32 presc_param, | ||
| 186 | u32 aac_timing_param) | ||
| 187 | { | ||
| 188 | u32 Tvib_us; | ||
| 189 | u32 ot_multi_base100; | ||
| 190 | u32 clk_dividing_rate_base100; | ||
| 191 | |||
| 192 | ot_multi_base100 = dw9768_find_ot_multi(aac_mode_param); | ||
| 193 | |||
| 194 | clk_dividing_rate_base100 = dw9768_find_dividing_rate(presc_param); | ||
| 195 | |||
| 196 | Tvib_us = (DW9768_TVIB_MS_BASE10 + aac_timing_param) * | ||
| 197 | clk_dividing_rate_base100; | ||
| 198 | |||
| 199 | return Tvib_us * ot_multi_base100 / 100; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int dw9768_mod_reg(struct dw9768 *dw9768, u8 reg, u8 mask, u8 val) | ||
| 203 | { | ||
| 204 | struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); | ||
| 205 | int ret; | ||
| 206 | |||
| 207 | ret = i2c_smbus_read_byte_data(client, reg); | ||
| 208 | if (ret < 0) | ||
| 209 | return ret; | ||
| 210 | |||
| 211 | val = ((unsigned char)ret & ~mask) | (val & mask); | ||
| 212 | |||
| 213 | return i2c_smbus_write_byte_data(client, reg, val); | ||
| 214 | } | ||
| 215 | |||
| 216 | static int dw9768_set_dac(struct dw9768 *dw9768, u16 val) | ||
| 217 | { | ||
| 218 | struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); | ||
| 219 | |||
| 220 | /* Write VCM position to registers */ | ||
| 221 | return i2c_smbus_write_word_swapped(client, DW9768_MSB_ADDR, val); | ||
| 222 | } | ||
| 223 | |||
| 224 | static int dw9768_init(struct dw9768 *dw9768) | ||
| 225 | { | ||
| 226 | struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); | ||
| 227 | int ret, val; | ||
| 228 | |||
| 229 | /* Reset DW9768_RING_PD_CONTROL_REG to default status 0x00 */ | ||
| 230 | ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG, | ||
| 231 | DW9768_PD_MODE_OFF); | ||
| 232 | if (ret < 0) | ||
| 233 | return ret; | ||
| 234 | |||
| 235 | /* | ||
| 236 | * DW9769 requires waiting delay time of t_OPR | ||
| 237 | * after PD reset takes place. | ||
| 238 | */ | ||
| 239 | usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100); | ||
| 240 | |||
| 241 | /* Set DW9768_RING_PD_CONTROL_REG to DW9768_AAC_MODE_EN(0x01) */ | ||
| 242 | ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG, | ||
| 243 | DW9768_AAC_MODE_EN); | ||
| 244 | if (ret < 0) | ||
| 245 | return ret; | ||
| 246 | |||
| 247 | /* Set AAC mode */ | ||
| 248 | ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG, | ||
| 249 | DW9768_AAC_MODE_SEL_MASK, | ||
| 250 | dw9768->aac_mode << 5); | ||
| 251 | if (ret < 0) | ||
| 252 | return ret; | ||
| 253 | |||
| 254 | /* Set clock presc */ | ||
| 255 | if (dw9768->clock_presc != DW9768_CLOCK_PRE_SCALE_DEFAULT) { | ||
| 256 | ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG, | ||
| 257 | DW9768_CLOCK_PRE_SCALE_SEL_MASK, | ||
| 258 | dw9768->clock_presc); | ||
| 259 | if (ret < 0) | ||
| 260 | return ret; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* Set AAC Timing */ | ||
| 264 | if (dw9768->aac_timing != DW9768_AAC_TIME_DEFAULT) { | ||
| 265 | ret = i2c_smbus_write_byte_data(client, DW9768_AAC_TIME_REG, | ||
| 266 | dw9768->aac_timing); | ||
| 267 | if (ret < 0) | ||
| 268 | return ret; | ||
| 269 | } | ||
| 270 | |||
| 271 | for (val = dw9768->focus->val % DW9768_MOVE_STEPS; | ||
| 272 | val <= dw9768->focus->val; | ||
| 273 | val += DW9768_MOVE_STEPS) { | ||
| 274 | ret = dw9768_set_dac(dw9768, val); | ||
| 275 | if (ret) { | ||
| 276 | dev_err(&client->dev, "I2C failure: %d", ret); | ||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | usleep_range(dw9768->move_delay_us, | ||
| 280 | dw9768->move_delay_us + 1000); | ||
| 281 | } | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static int dw9768_release(struct dw9768 *dw9768) | ||
| 287 | { | ||
| 288 | struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); | ||
| 289 | int ret, val; | ||
| 290 | |||
| 291 | val = round_down(dw9768->focus->val, DW9768_MOVE_STEPS); | ||
| 292 | for ( ; val >= 0; val -= DW9768_MOVE_STEPS) { | ||
| 293 | ret = dw9768_set_dac(dw9768, val); | ||
| 294 | if (ret) { | ||
| 295 | dev_err(&client->dev, "I2C write fail: %d", ret); | ||
| 296 | return ret; | ||
| 297 | } | ||
| 298 | usleep_range(dw9768->move_delay_us, | ||
| 299 | dw9768->move_delay_us + 1000); | ||
| 300 | } | ||
| 301 | |||
| 302 | ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG, | ||
| 303 | DW9768_PD_MODE_EN); | ||
| 304 | if (ret < 0) | ||
| 305 | return ret; | ||
| 306 | |||
| 307 | /* | ||
| 308 | * DW9769 requires waiting delay time of t_OPR | ||
| 309 | * after PD reset takes place. | ||
| 310 | */ | ||
| 311 | usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100); | ||
| 312 | |||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | static int dw9768_runtime_suspend(struct device *dev) | ||
| 317 | { | ||
| 318 | struct i2c_client *client = to_i2c_client(dev); | ||
| 319 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
| 320 | struct dw9768 *dw9768 = sd_to_dw9768(sd); | ||
| 321 | |||
| 322 | dw9768_release(dw9768); | ||
| 323 | regulator_bulk_disable(ARRAY_SIZE(dw9768_supply_names), | ||
| 324 | dw9768->supplies); | ||
| 325 | |||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int dw9768_runtime_resume(struct device *dev) | ||
| 330 | { | ||
| 331 | struct i2c_client *client = to_i2c_client(dev); | ||
| 332 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
| 333 | struct dw9768 *dw9768 = sd_to_dw9768(sd); | ||
| 334 | int ret; | ||
| 335 | |||
| 336 | ret = regulator_bulk_enable(ARRAY_SIZE(dw9768_supply_names), | ||
| 337 | dw9768->supplies); | ||
| 338 | if (ret < 0) { | ||
| 339 | dev_err(dev, "failed to enable regulators\n"); | ||
| 340 | return ret; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* | ||
| 344 | * The datasheet refers to t_OPR that needs to be waited before sending | ||
| 345 | * I2C commands after power-up. | ||
| 346 | */ | ||
| 347 | usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100); | ||
| 348 | |||
| 349 | ret = dw9768_init(dw9768); | ||
| 350 | if (ret < 0) | ||
| 351 | goto disable_regulator; | ||
| 352 | |||
| 353 | return 0; | ||
| 354 | |||
| 355 | disable_regulator: | ||
| 356 | regulator_bulk_disable(ARRAY_SIZE(dw9768_supply_names), | ||
| 357 | dw9768->supplies); | ||
| 358 | |||
| 359 | return ret; | ||
| 360 | } | ||
| 361 | |||
| 362 | static int dw9768_set_ctrl(struct v4l2_ctrl *ctrl) | ||
| 363 | { | ||
| 364 | struct dw9768 *dw9768 = container_of(ctrl->handler, | ||
| 365 | struct dw9768, ctrls); | ||
| 366 | |||
| 367 | if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) | ||
| 368 | return dw9768_set_dac(dw9768, ctrl->val); | ||
| 369 | |||
| 370 | return 0; | ||
| 371 | } | ||
| 372 | |||
| 373 | static const struct v4l2_ctrl_ops dw9768_ctrl_ops = { | ||
| 374 | .s_ctrl = dw9768_set_ctrl, | ||
| 375 | }; | ||
| 376 | |||
| 377 | static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
| 378 | { | ||
| 379 | int ret; | ||
| 380 | |||
| 381 | ret = pm_runtime_get_sync(sd->dev); | ||
| 382 | if (ret < 0) { | ||
| 383 | pm_runtime_put_noidle(sd->dev); | ||
| 384 | return ret; | ||
| 385 | } | ||
| 386 | |||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
| 391 | { | ||
| 392 | pm_runtime_put(sd->dev); | ||
| 393 | |||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | static const struct v4l2_subdev_internal_ops dw9768_int_ops = { | ||
| 398 | .open = dw9768_open, | ||
| 399 | .close = dw9768_close, | ||
| 400 | }; | ||
| 401 | |||
| 402 | static const struct v4l2_subdev_ops dw9768_ops = { }; | ||
| 403 | |||
| 404 | static int dw9768_init_controls(struct dw9768 *dw9768) | ||
| 405 | { | ||
| 406 | struct v4l2_ctrl_handler *hdl = &dw9768->ctrls; | ||
| 407 | const struct v4l2_ctrl_ops *ops = &dw9768_ctrl_ops; | ||
| 408 | |||
| 409 | v4l2_ctrl_handler_init(hdl, 1); | ||
| 410 | |||
| 411 | dw9768->focus = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, 0, | ||
| 412 | DW9768_MAX_FOCUS_POS, | ||
| 413 | DW9768_FOCUS_STEPS, 0); | ||
| 414 | |||
| 415 | if (hdl->error) | ||
| 416 | return hdl->error; | ||
| 417 | |||
| 418 | dw9768->sd.ctrl_handler = hdl; | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | static int dw9768_probe(struct i2c_client *client) | ||
| 424 | { | ||
| 425 | struct device *dev = &client->dev; | ||
| 426 | struct dw9768 *dw9768; | ||
| 427 | unsigned int i; | ||
| 428 | int ret; | ||
| 429 | |||
| 430 | dw9768 = devm_kzalloc(dev, sizeof(*dw9768), GFP_KERNEL); | ||
| 431 | if (!dw9768) | ||
| 432 | return -ENOMEM; | ||
| 433 | |||
| 434 | /* Initialize subdev */ | ||
| 435 | v4l2_i2c_subdev_init(&dw9768->sd, client, &dw9768_ops); | ||
| 436 | |||
| 437 | dw9768->aac_mode = DW9768_AAC_MODE_DEFAULT; | ||
| 438 | dw9768->aac_timing = DW9768_AAC_TIME_DEFAULT; | ||
| 439 | dw9768->clock_presc = DW9768_CLOCK_PRE_SCALE_DEFAULT; | ||
| 440 | |||
| 441 | /* Optional indication of AAC mode select */ | ||
| 442 | fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-mode", | ||
| 443 | &dw9768->aac_mode); | ||
| 444 | |||
| 445 | /* Optional indication of clock pre-scale select */ | ||
| 446 | fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,clock-presc", | ||
| 447 | &dw9768->clock_presc); | ||
| 448 | |||
| 449 | /* Optional indication of AAC Timing */ | ||
| 450 | fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-timing", | ||
| 451 | &dw9768->aac_timing); | ||
| 452 | |||
| 453 | dw9768->move_delay_us = dw9768_cal_move_delay(dw9768->aac_mode, | ||
| 454 | dw9768->clock_presc, | ||
| 455 | dw9768->aac_timing); | ||
| 456 | |||
| 457 | for (i = 0; i < ARRAY_SIZE(dw9768_supply_names); i++) | ||
| 458 | dw9768->supplies[i].supply = dw9768_supply_names[i]; | ||
| 459 | |||
| 460 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dw9768_supply_names), | ||
| 461 | dw9768->supplies); | ||
| 462 | if (ret) { | ||
| 463 | dev_err(dev, "failed to get regulators\n"); | ||
| 464 | return ret; | ||
| 465 | } | ||
| 466 | |||
| 467 | /* Initialize controls */ | ||
| 468 | ret = dw9768_init_controls(dw9768); | ||
| 469 | if (ret) | ||
| 470 | goto err_free_handler; | ||
| 471 | |||
| 472 | /* Initialize subdev */ | ||
| 473 | dw9768->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 474 | dw9768->sd.internal_ops = &dw9768_int_ops; | ||
| 475 | |||
| 476 | ret = media_entity_pads_init(&dw9768->sd.entity, 0, NULL); | ||
| 477 | if (ret < 0) | ||
| 478 | goto err_free_handler; | ||
| 479 | |||
| 480 | dw9768->sd.entity.function = MEDIA_ENT_F_LENS; | ||
| 481 | |||
| 482 | pm_runtime_enable(dev); | ||
| 483 | if (!pm_runtime_enabled(dev)) { | ||
| 484 | ret = dw9768_runtime_resume(dev); | ||
| 485 | if (ret < 0) { | ||
| 486 | dev_err(dev, "failed to power on: %d\n", ret); | ||
| 487 | goto err_clean_entity; | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | ret = v4l2_async_register_subdev(&dw9768->sd); | ||
| 492 | if (ret < 0) { | ||
| 493 | dev_err(dev, "failed to register V4L2 subdev: %d", ret); | ||
| 494 | goto err_power_off; | ||
| 495 | } | ||
| 496 | |||
| 497 | return 0; | ||
| 498 | |||
| 499 | err_power_off: | ||
| 500 | if (pm_runtime_enabled(dev)) | ||
| 501 | pm_runtime_disable(dev); | ||
| 502 | else | ||
| 503 | dw9768_runtime_suspend(dev); | ||
| 504 | err_clean_entity: | ||
| 505 | media_entity_cleanup(&dw9768->sd.entity); | ||
| 506 | err_free_handler: | ||
| 507 | v4l2_ctrl_handler_free(&dw9768->ctrls); | ||
| 508 | |||
| 509 | return ret; | ||
| 510 | } | ||
| 511 | |||
| 512 | static int dw9768_remove(struct i2c_client *client) | ||
| 513 | { | ||
| 514 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
| 515 | struct dw9768 *dw9768 = sd_to_dw9768(sd); | ||
| 516 | |||
| 517 | v4l2_async_unregister_subdev(&dw9768->sd); | ||
| 518 | v4l2_ctrl_handler_free(&dw9768->ctrls); | ||
| 519 | media_entity_cleanup(&dw9768->sd.entity); | ||
| 520 | pm_runtime_disable(&client->dev); | ||
| 521 | if (!pm_runtime_status_suspended(&client->dev)) | ||
| 522 | dw9768_runtime_suspend(&client->dev); | ||
| 523 | pm_runtime_set_suspended(&client->dev); | ||
| 524 | |||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | static const struct of_device_id dw9768_of_table[] = { | ||
| 529 | { .compatible = "dongwoon,dw9768" }, | ||
| 530 | { .compatible = "giantec,gt9769" }, | ||
| 531 | {} | ||
| 532 | }; | ||
| 533 | MODULE_DEVICE_TABLE(of, dw9768_of_table); | ||
| 534 | |||
| 535 | static const struct dev_pm_ops dw9768_pm_ops = { | ||
| 536 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
| 537 | pm_runtime_force_resume) | ||
| 538 | SET_RUNTIME_PM_OPS(dw9768_runtime_suspend, dw9768_runtime_resume, NULL) | ||
| 539 | }; | ||
| 540 | |||
| 541 | static struct i2c_driver dw9768_i2c_driver = { | ||
| 542 | .driver = { | ||
| 543 | .name = DW9768_NAME, | ||
| 544 | .pm = &dw9768_pm_ops, | ||
| 545 | .of_match_table = dw9768_of_table, | ||
| 546 | }, | ||
| 547 | .probe_new = dw9768_probe, | ||
| 548 | .remove = dw9768_remove, | ||
| 549 | }; | ||
| 550 | module_i2c_driver(dw9768_i2c_driver); | ||
| 551 | |||
| 552 | MODULE_AUTHOR("Dongchun Zhu <dongchun.zhu@mediatek.com>"); | ||
| 553 | MODULE_DESCRIPTION("DW9768 VCM driver"); | ||
| 554 | MODULE_LICENSE("GPL v2"); | ||
| @@ -25,9 +25,19 @@ · 24 unmodified lines | |||
| 25 | #define IMX290_STANDBY 0x3000 | 25 | #define IMX290_STANDBY 0x3000 |
| 26 | #define IMX290_REGHOLD 0x3001 | 26 | #define IMX290_REGHOLD 0x3001 |
| 27 | #define IMX290_XMSTA 0x3002 | 27 | #define IMX290_XMSTA 0x3002 |
| 28 | #define IMX290_FR_FDG_SEL 0x3009 | ||
| 29 | #define IMX290_BLKLEVEL_LOW 0x300a | ||
| 30 | #define IMX290_BLKLEVEL_HIGH 0x300b | ||
| 28 | #define IMX290_GAIN 0x3014 | 31 | #define IMX290_GAIN 0x3014 |
| 32 | #define IMX290_HMAX_LOW 0x301c | ||
| 33 | #define IMX290_HMAX_HIGH 0x301d | ||
| 34 | #define IMX290_PGCTRL 0x308c | ||
| 35 | #define IMX290_PHY_LANE_NUM 0x3407 | ||
| 36 | #define IMX290_CSI_LANE_MODE 0x3443 | ||
| 29 | 37 | ||
| 30 | #define IMX290_DEFAULT_LINK_FREQ 445500000 | 38 | #define IMX290_PGCTRL_REGEN BIT(0) |
| 39 | #define IMX290_PGCTRL_THRU BIT(1) | ||
| 40 | #define IMX290_PGCTRL_MODE(n) ((n) << 4) | ||
| 31 | 41 | ||
| 32 | static const char * const imx290_supply_name[] = { | 42 | static const char * const imx290_supply_name[] = { |
| 33 | "vdda", | 43 | "vdda", |
| @@ -45,8 +55,8 @@ struct imx290_regval { · 11 unmodified lines | |||
| 45 | struct imx290_mode { | 55 | struct imx290_mode { |
| 46 | u32 width; | 56 | u32 width; |
| 47 | u32 height; | 57 | u32 height; |
| 48 | u32 pixel_rate; | 58 | u32 hmax; |
| 49 | u32 link_freq_index; | 59 | u8 link_freq_index; |
| 50 | 60 | ||
| 51 | const struct imx290_regval *data; | 61 | const struct imx290_regval *data; |
| 52 | u32 data_size; | 62 | u32 data_size; |
| @@ -56,9 +66,10 @@ struct imx290 { · 3 unmodified lines | |||
| 56 | struct device *dev; | 66 | struct device *dev; |
| 57 | struct clk *xclk; | 67 | struct clk *xclk; |
| 58 | struct regmap *regmap; | 68 | struct regmap *regmap; |
| 69 | u8 nlanes; | ||
| 70 | u8 bpp; | ||
| 59 | 71 | ||
| 60 | struct v4l2_subdev sd; | 72 | struct v4l2_subdev sd; |
| 61 | struct v4l2_fwnode_endpoint ep; | ||
| 62 | struct media_pad pad; | 73 | struct media_pad pad; |
| 63 | struct v4l2_mbus_framefmt current_format; | 74 | struct v4l2_mbus_framefmt current_format; |
| 64 | const struct imx290_mode *current_mode; | 75 | const struct imx290_mode *current_mode; |
| @@ -75,10 +86,12 @@ struct imx290 { · 10 unmodified lines | |||
| 75 | 86 | ||
| 76 | struct imx290_pixfmt { | 87 | struct imx290_pixfmt { |
| 77 | u32 code; | 88 | u32 code; |
| 89 | u8 bpp; | ||
| 78 | }; | 90 | }; |
| 79 | 91 | ||
| 80 | static const struct imx290_pixfmt imx290_formats[] = { | 92 | static const struct imx290_pixfmt imx290_formats[] = { |
| 81 | { MEDIA_BUS_FMT_SRGGB10_1X10 }, | 93 | { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, |
| 94 | { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, | ||
| 82 | }; | 95 | }; |
| 83 | 96 | ||
| 84 | static const struct regmap_config imx290_regmap_config = { | 97 | static const struct regmap_config imx290_regmap_config = { |
| @@ -87,16 +100,24 @@ static const struct regmap_config imx290_regmap_config = { · 2 unmodified lines | |||
| 87 | .cache_type = REGCACHE_RBTREE, | 100 | .cache_type = REGCACHE_RBTREE, |
| 88 | }; | 101 | }; |
| 89 | 102 | ||
| 103 | static const char * const imx290_test_pattern_menu[] = { | ||
| 104 | "Disabled", | ||
| 105 | "Sequence Pattern 1", | ||
| 106 | "Horizontal Color-bar Chart", | ||
| 107 | "Vertical Color-bar Chart", | ||
| 108 | "Sequence Pattern 2", | ||
| 109 | "Gradation Pattern 1", | ||
| 110 | "Gradation Pattern 2", | ||
| 111 | "000/555h Toggle Pattern", | ||
| 112 | }; | ||
| 113 | |||
| 90 | static const struct imx290_regval imx290_global_init_settings[] = { | 114 | static const struct imx290_regval imx290_global_init_settings[] = { |
| 91 | { 0x3007, 0x00 }, | 115 | { 0x3007, 0x00 }, |
| 92 | { 0x3009, 0x00 }, | ||
| 93 | { 0x3018, 0x65 }, | 116 | { 0x3018, 0x65 }, |
| 94 | { 0x3019, 0x04 }, | 117 | { 0x3019, 0x04 }, |
| 95 | { 0x301a, 0x00 }, | 118 | { 0x301a, 0x00 }, |
| 96 | { 0x3443, 0x03 }, | ||
| 97 | { 0x3444, 0x20 }, | 119 | { 0x3444, 0x20 }, |
| 98 | { 0x3445, 0x25 }, | 120 | { 0x3445, 0x25 }, |
| 99 | { 0x3407, 0x03 }, | ||
| 100 | { 0x303a, 0x0c }, | 121 | { 0x303a, 0x0c }, |
| 101 | { 0x3040, 0x00 }, | 122 | { 0x3040, 0x00 }, |
| 102 | { 0x3041, 0x00 }, | 123 | { 0x3041, 0x00 }, |
| @@ -169,7 +190,6 @@ static const struct imx290_regval imx290_1080p_settings[] = { · 66 unmodified lines | |||
| 169 | { 0x3164, 0x1a }, | 190 | { 0x3164, 0x1a }, |
| 170 | { 0x3480, 0x49 }, | 191 | { 0x3480, 0x49 }, |
| 171 | /* data rate settings */ | 192 | /* data rate settings */ |
| 172 | { 0x3009, 0x01 }, | ||
| 173 | { 0x3405, 0x10 }, | 193 | { 0x3405, 0x10 }, |
| 174 | { 0x3446, 0x57 }, | 194 | { 0x3446, 0x57 }, |
| 175 | { 0x3447, 0x00 }, | 195 | { 0x3447, 0x00 }, |
| @@ -187,8 +207,6 @@ static const struct imx290_regval imx290_1080p_settings[] = { · 11 unmodified lines | |||
| 187 | { 0x3453, 0x00 }, | 207 | { 0x3453, 0x00 }, |
| 188 | { 0x3454, 0x17 }, | 208 | { 0x3454, 0x17 }, |
| 189 | { 0x3455, 0x00 }, | 209 | { 0x3455, 0x00 }, |
| 190 | { 0x301c, 0x98 }, | ||
| 191 | { 0x301d, 0x08 }, | ||
| 192 | }; | 210 | }; |
| 193 | 211 | ||
| 194 | static const struct imx290_regval imx290_720p_settings[] = { | 212 | static const struct imx290_regval imx290_720p_settings[] = { |
| @@ -210,7 +228,6 @@ static const struct imx290_regval imx290_720p_settings[] = { · 15 unmodified lines | |||
| 210 | { 0x3164, 0x1a }, | 228 | { 0x3164, 0x1a }, |
| 211 | { 0x3480, 0x49 }, | 229 | { 0x3480, 0x49 }, |
| 212 | /* data rate settings */ | 230 | /* data rate settings */ |
| 213 | { 0x3009, 0x01 }, | ||
| 214 | { 0x3405, 0x10 }, | 231 | { 0x3405, 0x10 }, |
| 215 | { 0x3446, 0x4f }, | 232 | { 0x3446, 0x4f }, |
| 216 | { 0x3447, 0x00 }, | 233 | { 0x3447, 0x00 }, |
| @@ -228,8 +245,6 @@ static const struct imx290_regval imx290_720p_settings[] = { · 11 unmodified lines | |||
| 228 | { 0x3453, 0x00 }, | 245 | { 0x3453, 0x00 }, |
| 229 | { 0x3454, 0x17 }, | 246 | { 0x3454, 0x17 }, |
| 230 | { 0x3455, 0x00 }, | 247 | { 0x3455, 0x00 }, |
| 231 | { 0x301c, 0xe4 }, | ||
| 232 | { 0x301d, 0x0c }, | ||
| 233 | }; | 248 | }; |
| 234 | 249 | ||
| 235 | static const struct imx290_regval imx290_10bit_settings[] = { | 250 | static const struct imx290_regval imx290_10bit_settings[] = { |
| @@ -244,31 +259,105 @@ static const struct imx290_regval imx290_10bit_settings[] = { · 8 unmodified lines | |||
| 244 | { 0x300b, 0x00}, | 259 | { 0x300b, 0x00}, |
| 245 | }; | 260 | }; |
| 246 | 261 | ||
| 262 | static const struct imx290_regval imx290_12bit_settings[] = { | ||
| 263 | { 0x3005, 0x01 }, | ||
| 264 | { 0x3046, 0x01 }, | ||
| 265 | { 0x3129, 0x00 }, | ||
| 266 | { 0x317c, 0x00 }, | ||
| 267 | { 0x31ec, 0x0e }, | ||
| 268 | { 0x3441, 0x0c }, | ||
| 269 | { 0x3442, 0x0c }, | ||
| 270 | { 0x300a, 0xf0 }, | ||
| 271 | { 0x300b, 0x00 }, | ||
| 272 | }; | ||
| 273 | |||
| 247 | /* supported link frequencies */ | 274 | /* supported link frequencies */ |
| 248 | static const s64 imx290_link_freq[] = { | 275 | #define FREQ_INDEX_1080P 0 |
| 249 | IMX290_DEFAULT_LINK_FREQ, | 276 | #define FREQ_INDEX_720P 1 |
| 277 | static const s64 imx290_link_freq_2lanes[] = { | ||
| 278 | [FREQ_INDEX_1080P] = 445500000, | ||
| 279 | [FREQ_INDEX_720P] = 297000000, | ||
| 250 | }; | 280 | }; |
| 281 | static const s64 imx290_link_freq_4lanes[] = { | ||
| 282 | [FREQ_INDEX_1080P] = 222750000, | ||
| 283 | [FREQ_INDEX_720P] = 148500000, | ||
| 284 | }; | ||
| 285 | |||
| 286 | /* | ||
| 287 | * In this function and in the similar ones below We rely on imx290_probe() | ||
| 288 | * to ensure that nlanes is either 2 or 4. | ||
| 289 | */ | ||
| 290 | static inline const s64 *imx290_link_freqs_ptr(const struct imx290 *imx290) | ||
| 291 | { | ||
| 292 | if (imx290->nlanes == 2) | ||
| 293 | return imx290_link_freq_2lanes; | ||
| 294 | else | ||
| 295 | return imx290_link_freq_4lanes; | ||
| 296 | } | ||
| 297 | |||
| 298 | static inline int imx290_link_freqs_num(const struct imx290 *imx290) | ||
| 299 | { | ||
| 300 | if (imx290->nlanes == 2) | ||
| 301 | return ARRAY_SIZE(imx290_link_freq_2lanes); | ||
| 302 | else | ||
| 303 | return ARRAY_SIZE(imx290_link_freq_4lanes); | ||
| 304 | } | ||
| 251 | 305 | ||
| 252 | /* Mode configs */ | 306 | /* Mode configs */ |
| 253 | static const struct imx290_mode imx290_modes[] = { | 307 | static const struct imx290_mode imx290_modes_2lanes[] = { |
| 308 | { | ||
| 309 | .width = 1920, | ||
| 310 | .height = 1080, | ||
| 311 | .hmax = 0x1130, | ||
| 312 | .link_freq_index = FREQ_INDEX_1080P, | ||
| 313 | .data = imx290_1080p_settings, | ||
| 314 | .data_size = ARRAY_SIZE(imx290_1080p_settings), | ||
| 315 | }, | ||
| 316 | { | ||
| 317 | .width = 1280, | ||
| 318 | .height = 720, | ||
| 319 | .hmax = 0x19c8, | ||
| 320 | .link_freq_index = FREQ_INDEX_720P, | ||
| 321 | .data = imx290_720p_settings, | ||
| 322 | .data_size = ARRAY_SIZE(imx290_720p_settings), | ||
| 323 | }, | ||
| 324 | }; | ||
| 325 | |||
| 326 | static const struct imx290_mode imx290_modes_4lanes[] = { | ||
| 254 | { | 327 | { |
| 255 | .width = 1920, | 328 | .width = 1920, |
| 256 | .height = 1080, | 329 | .height = 1080, |
| 330 | .hmax = 0x0898, | ||
| 331 | .link_freq_index = FREQ_INDEX_1080P, | ||
| 257 | .data = imx290_1080p_settings, | 332 | .data = imx290_1080p_settings, |
| 258 | .data_size = ARRAY_SIZE(imx290_1080p_settings), | 333 | .data_size = ARRAY_SIZE(imx290_1080p_settings), |
| 259 | .pixel_rate = 178200000, | ||
| 260 | .link_freq_index = 0, | ||
| 261 | }, | 334 | }, |
| 262 | { | 335 | { |
| 263 | .width = 1280, | 336 | .width = 1280, |
| 264 | .height = 720, | 337 | .height = 720, |
| 338 | .hmax = 0x0ce4, | ||
| 339 | .link_freq_index = FREQ_INDEX_720P, | ||
| 265 | .data = imx290_720p_settings, | 340 | .data = imx290_720p_settings, |
| 266 | .data_size = ARRAY_SIZE(imx290_720p_settings), | 341 | .data_size = ARRAY_SIZE(imx290_720p_settings), |
| 267 | .pixel_rate = 178200000, | ||
| 268 | .link_freq_index = 0, | ||
| 269 | }, | 342 | }, |
| 270 | }; | 343 | }; |
| 271 | 344 | ||
| 345 | static inline const struct imx290_mode *imx290_modes_ptr(const struct imx290 *imx290) | ||
| 346 | { | ||
| 347 | if (imx290->nlanes == 2) | ||
| 348 | return imx290_modes_2lanes; | ||
| 349 | else | ||
| 350 | return imx290_modes_4lanes; | ||
| 351 | } | ||
| 352 | |||
| 353 | static inline int imx290_modes_num(const struct imx290 *imx290) | ||
| 354 | { | ||
| 355 | if (imx290->nlanes == 2) | ||
| 356 | return ARRAY_SIZE(imx290_modes_2lanes); | ||
| 357 | else | ||
| 358 | return ARRAY_SIZE(imx290_modes_4lanes); | ||
| 359 | } | ||
| 360 | |||
| 272 | static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) | 361 | static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) |
| 273 | { | 362 | { |
| 274 | return container_of(_sd, struct imx290, sd); | 363 | return container_of(_sd, struct imx290, sd); |
| @@ -314,11 +403,11 @@ static int imx290_set_register_array(struct imx290 *imx290, · 39 unmodified lines | |||
| 314 | ret = imx290_write_reg(imx290, settings->reg, settings->val); | 403 | ret = imx290_write_reg(imx290, settings->reg, settings->val); |
| 315 | if (ret < 0) | 404 | if (ret < 0) |
| 316 | return ret; | 405 | return ret; |
| 317 | |||
| 318 | /* Settle time is 10ms for all registers */ | ||
| 319 | msleep(10); | ||
| 320 | } | 406 | } |
| 321 | 407 | ||
| 408 | /* Provide 10ms settle time */ | ||
| 409 | usleep_range(10000, 11000); | ||
| 410 | |||
| 322 | return 0; | 411 | return 0; |
| 323 | } | 412 | } |
| 324 | 413 | ||
| @@ -391,6 +480,27 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) · 66 unmodified lines | |||
| 391 | case V4L2_CID_GAIN: | 480 | case V4L2_CID_GAIN: |
| 392 | ret = imx290_set_gain(imx290, ctrl->val); | 481 | ret = imx290_set_gain(imx290, ctrl->val); |
| 393 | break; | 482 | break; |
| 483 | case V4L2_CID_TEST_PATTERN: | ||
| 484 | if (ctrl->val) { | ||
| 485 | imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00); | ||
| 486 | imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00); | ||
| 487 | usleep_range(10000, 11000); | ||
| 488 | imx290_write_reg(imx290, IMX290_PGCTRL, | ||
| 489 | (u8)(IMX290_PGCTRL_REGEN | | ||
| 490 | IMX290_PGCTRL_THRU | | ||
| 491 | IMX290_PGCTRL_MODE(ctrl->val))); | ||
| 492 | } else { | ||
| 493 | imx290_write_reg(imx290, IMX290_PGCTRL, 0x00); | ||
| 494 | usleep_range(10000, 11000); | ||
| 495 | if (imx290->bpp == 10) | ||
| 496 | imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, | ||
| 497 | 0x3c); | ||
| 498 | else /* 12 bits per pixel */ | ||
| 499 | imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, | ||
| 500 | 0xf0); | ||
| 501 | imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00); | ||
| 502 | } | ||
| 503 | break; | ||
| 394 | default: | 504 | default: |
| 395 | ret = -EINVAL; | 505 | ret = -EINVAL; |
| 396 | break; | 506 | break; |
| @@ -417,6 +527,28 @@ static int imx290_enum_mbus_code(struct v4l2_subdev *sd, · 20 unmodified lines | |||
| 417 | return 0; | 527 | return 0; |
| 418 | } | 528 | } |
| 419 | 529 | ||
| 530 | static int imx290_enum_frame_size(struct v4l2_subdev *sd, | ||
| 531 | struct v4l2_subdev_pad_config *cfg, | ||
| 532 | struct v4l2_subdev_frame_size_enum *fse) | ||
| 533 | { | ||
| 534 | const struct imx290 *imx290 = to_imx290(sd); | ||
| 535 | const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); | ||
| 536 | |||
| 537 | if ((fse->code != imx290_formats[0].code) && | ||
| 538 | (fse->code != imx290_formats[1].code)) | ||
| 539 | return -EINVAL; | ||
| 540 | |||
| 541 | if (fse->index >= imx290_modes_num(imx290)) | ||
| 542 | return -EINVAL; | ||
| 543 | |||
| 544 | fse->min_width = imx290_modes[fse->index].width; | ||
| 545 | fse->max_width = imx290_modes[fse->index].width; | ||
| 546 | fse->min_height = imx290_modes[fse->index].height; | ||
| 547 | fse->max_height = imx290_modes[fse->index].height; | ||
| 548 | |||
| 549 | return 0; | ||
| 550 | } | ||
| 551 | |||
| 420 | static int imx290_get_fmt(struct v4l2_subdev *sd, | 552 | static int imx290_get_fmt(struct v4l2_subdev *sd, |
| 421 | struct v4l2_subdev_pad_config *cfg, | 553 | struct v4l2_subdev_pad_config *cfg, |
| 422 | struct v4l2_subdev_format *fmt) | 554 | struct v4l2_subdev_format *fmt) |
| @@ -439,6 +571,30 @@ static int imx290_get_fmt(struct v4l2_subdev *sd, · 16 unmodified lines | |||
| 439 | return 0; | 571 | return 0; |
| 440 | } | 572 | } |
| 441 | 573 | ||
| 574 | static inline u8 imx290_get_link_freq_index(struct imx290 *imx290) | ||
| 575 | { | ||
| 576 | return imx290->current_mode->link_freq_index; | ||
| 577 | } | ||
| 578 | |||
| 579 | static s64 imx290_get_link_freq(struct imx290 *imx290) | ||
| 580 | { | ||
| 581 | u8 index = imx290_get_link_freq_index(imx290); | ||
| 582 | |||
| 583 | return *(imx290_link_freqs_ptr(imx290) + index); | ||
| 584 | } | ||
| 585 | |||
| 586 | static u64 imx290_calc_pixel_rate(struct imx290 *imx290) | ||
| 587 | { | ||
| 588 | s64 link_freq = imx290_get_link_freq(imx290); | ||
| 589 | u8 nlanes = imx290->nlanes; | ||
| 590 | u64 pixel_rate; | ||
| 591 | |||
| 592 | /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ | ||
| 593 | pixel_rate = link_freq * 2 * nlanes; | ||
| 594 | do_div(pixel_rate, imx290->bpp); | ||
| 595 | return pixel_rate; | ||
| 596 | } | ||
| 597 | |||
| 442 | static int imx290_set_fmt(struct v4l2_subdev *sd, | 598 | static int imx290_set_fmt(struct v4l2_subdev *sd, |
| 443 | struct v4l2_subdev_pad_config *cfg, | 599 | struct v4l2_subdev_pad_config *cfg, |
| 444 | struct v4l2_subdev_format *fmt) | 600 | struct v4l2_subdev_format *fmt) |
| @@ -450,9 +606,8 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, · 5 unmodified lines | |||
| 450 | 606 | ||
| 451 | mutex_lock(&imx290->lock); | 607 | mutex_lock(&imx290->lock); |
| 452 | 608 | ||
| 453 | mode = v4l2_find_nearest_size(imx290_modes, | 609 | mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290), |
| 454 | ARRAY_SIZE(imx290_modes), | 610 | imx290_modes_num(imx290), width, height, |
| 455 | width, height, | ||
| 456 | fmt->format.width, fmt->format.height); | 611 | fmt->format.width, fmt->format.height); |
| 457 | 612 | ||
| 458 | fmt->format.width = mode->width; | 613 | fmt->format.width = mode->width; |
| @@ -472,10 +627,15 @@ static int imx290_set_fmt(struct v4l2_subdev *sd, · 13 unmodified lines | |||
| 472 | format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); | 627 | format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
| 473 | } else { | 628 | } else { |
| 474 | format = &imx290->current_format; | 629 | format = &imx290->current_format; |
| 475 | __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); | ||
| 476 | __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, mode->pixel_rate); | ||
| 477 | |||
| 478 | imx290->current_mode = mode; | 630 | imx290->current_mode = mode; |
| 631 | imx290->bpp = imx290_formats[i].bpp; | ||
| 632 | |||
| 633 | if (imx290->link_freq) | ||
| 634 | __v4l2_ctrl_s_ctrl(imx290->link_freq, | ||
| 635 | imx290_get_link_freq_index(imx290)); | ||
| 636 | if (imx290->pixel_rate) | ||
| 637 | __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, | ||
| 638 | imx290_calc_pixel_rate(imx290)); | ||
| 479 | } | 639 | } |
| 480 | 640 | ||
| 481 | *format = fmt->format; | 641 | *format = fmt->format; |
| @@ -499,12 +659,11 @@ static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, · 17 unmodified lines | |||
| 499 | return 0; | 659 | return 0; |
| 500 | } | 660 | } |
| 501 | 661 | ||
| 502 | static int imx290_write_current_format(struct imx290 *imx290, | 662 | static int imx290_write_current_format(struct imx290 *imx290) |
| 503 | struct v4l2_mbus_framefmt *format) | ||
| 504 | { | 663 | { |
| 505 | int ret; | 664 | int ret; |
| 506 | 665 | ||
| 507 | switch (format->code) { | 666 | switch (imx290->current_format.code) { |
| 508 | case MEDIA_BUS_FMT_SRGGB10_1X10: | 667 | case MEDIA_BUS_FMT_SRGGB10_1X10: |
| 509 | ret = imx290_set_register_array(imx290, imx290_10bit_settings, | 668 | ret = imx290_set_register_array(imx290, imx290_10bit_settings, |
| 510 | ARRAY_SIZE( | 669 | ARRAY_SIZE( |
| @@ -514,6 +673,15 @@ static int imx290_write_current_format(struct imx290 *imx290, · 3 unmodified lines | |||
| 514 | return ret; | 673 | return ret; |
| 515 | } | 674 | } |
| 516 | break; | 675 | break; |
| 676 | case MEDIA_BUS_FMT_SRGGB12_1X12: | ||
| 677 | ret = imx290_set_register_array(imx290, imx290_12bit_settings, | ||
| 678 | ARRAY_SIZE( | ||
| 679 | imx290_12bit_settings)); | ||
| 680 | if (ret < 0) { | ||
| 681 | dev_err(imx290->dev, "Could not set format registers\n"); | ||
| 682 | return ret; | ||
| 683 | } | ||
| 684 | break; | ||
| 517 | default: | 685 | default: |
| 518 | dev_err(imx290->dev, "Unknown pixel format\n"); | 686 | dev_err(imx290->dev, "Unknown pixel format\n"); |
| 519 | return -EINVAL; | 687 | return -EINVAL; |
| @@ -522,6 +690,25 @@ static int imx290_write_current_format(struct imx290 *imx290, · 2 unmodified lines | |||
| 522 | return 0; | 690 | return 0; |
| 523 | } | 691 | } |
| 524 | 692 | ||
| 693 | static int imx290_set_hmax(struct imx290 *imx290, u32 val) | ||
| 694 | { | ||
| 695 | int ret; | ||
| 696 | |||
| 697 | ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff)); | ||
| 698 | if (ret) { | ||
| 699 | dev_err(imx290->dev, "Error setting HMAX register\n"); | ||
| 700 | return ret; | ||
| 701 | } | ||
| 702 | |||
| 703 | ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff)); | ||
| 704 | if (ret) { | ||
| 705 | dev_err(imx290->dev, "Error setting HMAX register\n"); | ||
| 706 | return ret; | ||
| 707 | } | ||
| 708 | |||
| 709 | return 0; | ||
| 710 | } | ||
| 711 | |||
| 525 | /* Start streaming */ | 712 | /* Start streaming */ |
| 526 | static int imx290_start_streaming(struct imx290 *imx290) | 713 | static int imx290_start_streaming(struct imx290 *imx290) |
| 527 | { | 714 | { |
| @@ -536,8 +723,8 @@ static int imx290_start_streaming(struct imx290 *imx290) · 8 unmodified lines | |||
| 536 | return ret; | 723 | return ret; |
| 537 | } | 724 | } |
| 538 | 725 | ||
| 539 | /* Set current frame format */ | 726 | /* Apply the register values related to current frame format */ |
| 540 | ret = imx290_write_current_format(imx290, &imx290->current_format); | 727 | ret = imx290_write_current_format(imx290); |
| 541 | if (ret < 0) { | 728 | if (ret < 0) { |
| 542 | dev_err(imx290->dev, "Could not set frame format\n"); | 729 | dev_err(imx290->dev, "Could not set frame format\n"); |
| 543 | return ret; | 730 | return ret; |
| @@ -550,6 +737,9 @@ static int imx290_start_streaming(struct imx290 *imx290) · 6 unmodified lines | |||
| 550 | dev_err(imx290->dev, "Could not set current mode\n"); | 737 | dev_err(imx290->dev, "Could not set current mode\n"); |
| 551 | return ret; | 738 | return ret; |
| 552 | } | 739 | } |
| 740 | ret = imx290_set_hmax(imx290, imx290->current_mode->hmax); | ||
| 741 | if (ret < 0) | ||
| 742 | return ret; | ||
| 553 | 743 | ||
| 554 | /* Apply customized values from user */ | 744 | /* Apply customized values from user */ |
| 555 | ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); | 745 | ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); |
| @@ -607,6 +797,49 @@ static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) · 51 unmodified lines | |||
| 607 | imx290->supplies); | 797 | imx290->supplies); |
| 608 | } | 798 | } |
| 609 | 799 | ||
| 800 | static int imx290_set_data_lanes(struct imx290 *imx290) | ||
| 801 | { | ||
| 802 | int ret = 0, laneval, frsel; | ||
| 803 | |||
| 804 | switch (imx290->nlanes) { | ||
| 805 | case 2: | ||
| 806 | laneval = 0x01; | ||
| 807 | frsel = 0x02; | ||
| 808 | break; | ||
| 809 | case 4: | ||
| 810 | laneval = 0x03; | ||
| 811 | frsel = 0x01; | ||
| 812 | break; | ||
| 813 | default: | ||
| 814 | /* | ||
| 815 | * We should never hit this since the data lane count is | ||
| 816 | * validated in probe itself | ||
| 817 | */ | ||
| 818 | dev_err(imx290->dev, "Lane configuration not supported\n"); | ||
| 819 | ret = -EINVAL; | ||
| 820 | goto exit; | ||
| 821 | } | ||
| 822 | |||
| 823 | ret = imx290_write_reg(imx290, IMX290_PHY_LANE_NUM, laneval); | ||
| 824 | if (ret) { | ||
| 825 | dev_err(imx290->dev, "Error setting Physical Lane number register\n"); | ||
| 826 | goto exit; | ||
| 827 | } | ||
| 828 | |||
| 829 | ret = imx290_write_reg(imx290, IMX290_CSI_LANE_MODE, laneval); | ||
| 830 | if (ret) { | ||
| 831 | dev_err(imx290->dev, "Error setting CSI Lane mode register\n"); | ||
| 832 | goto exit; | ||
| 833 | } | ||
| 834 | |||
| 835 | ret = imx290_write_reg(imx290, IMX290_FR_FDG_SEL, frsel); | ||
| 836 | if (ret) | ||
| 837 | dev_err(imx290->dev, "Error setting FR/FDG SEL register\n"); | ||
| 838 | |||
| 839 | exit: | ||
| 840 | return ret; | ||
| 841 | } | ||
| 842 | |||
| 610 | static int imx290_power_on(struct device *dev) | 843 | static int imx290_power_on(struct device *dev) |
| 611 | { | 844 | { |
| 612 | struct i2c_client *client = to_i2c_client(dev); | 845 | struct i2c_client *client = to_i2c_client(dev); |
| @@ -628,9 +861,12 @@ static int imx290_power_on(struct device *dev) · 15 unmodified lines | |||
| 628 | } | 861 | } |
| 629 | 862 | ||
| 630 | usleep_range(1, 2); | 863 | usleep_range(1, 2); |
| 631 | gpiod_set_value_cansleep(imx290->rst_gpio, 1); | 864 | gpiod_set_value_cansleep(imx290->rst_gpio, 0); |
| 632 | usleep_range(30000, 31000); | 865 | usleep_range(30000, 31000); |
| 633 | 866 | ||
| 867 | /* Set data lane count */ | ||
| 868 | imx290_set_data_lanes(imx290); | ||
| 869 | |||
| 634 | return 0; | 870 | return 0; |
| 635 | } | 871 | } |
| 636 | 872 | ||
| @@ -641,14 +877,14 @@ static int imx290_power_off(struct device *dev) · 4 unmodified lines | |||
| 641 | struct imx290 *imx290 = to_imx290(sd); | 877 | struct imx290 *imx290 = to_imx290(sd); |
| 642 | 878 | ||
| 643 | clk_disable_unprepare(imx290->xclk); | 879 | clk_disable_unprepare(imx290->xclk); |
| 644 | gpiod_set_value_cansleep(imx290->rst_gpio, 0); | 880 | gpiod_set_value_cansleep(imx290->rst_gpio, 1); |
| 645 | regulator_bulk_disable(IMX290_NUM_SUPPLIES, imx290->supplies); | 881 | regulator_bulk_disable(IMX290_NUM_SUPPLIES, imx290->supplies); |
| 646 | 882 | ||
| 647 | return 0; | 883 | return 0; |
| 648 | } | 884 | } |
| 649 | 885 | ||
| 650 | static const struct dev_pm_ops imx290_pm_ops = { | 886 | static const struct dev_pm_ops imx290_pm_ops = { |
| 651 | SET_RUNTIME_PM_OPS(imx290_power_on, imx290_power_off, NULL) | 887 | SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL) |
| 652 | }; | 888 | }; |
| 653 | 889 | ||
| 654 | static const struct v4l2_subdev_video_ops imx290_video_ops = { | 890 | static const struct v4l2_subdev_video_ops imx290_video_ops = { |
| @@ -658,6 +894,7 @@ static const struct v4l2_subdev_video_ops imx290_video_ops = { · 3 unmodified lines | |||
| 658 | static const struct v4l2_subdev_pad_ops imx290_pad_ops = { | 894 | static const struct v4l2_subdev_pad_ops imx290_pad_ops = { |
| 659 | .init_cfg = imx290_entity_init_cfg, | 895 | .init_cfg = imx290_entity_init_cfg, |
| 660 | .enum_mbus_code = imx290_enum_mbus_code, | 896 | .enum_mbus_code = imx290_enum_mbus_code, |
| 897 | .enum_frame_size = imx290_enum_frame_size, | ||
| 661 | .get_fmt = imx290_get_fmt, | 898 | .get_fmt = imx290_get_fmt, |
| 662 | .set_fmt = imx290_set_fmt, | 899 | .set_fmt = imx290_set_fmt, |
| 663 | }; | 900 | }; |
| @@ -671,12 +908,39 @@ static const struct media_entity_operations imx290_subdev_entity_ops = { · 7 unmodified lines | |||
| 671 | .link_validate = v4l2_subdev_link_validate, | 908 | .link_validate = v4l2_subdev_link_validate, |
| 672 | }; | 909 | }; |
| 673 | 910 | ||
| 911 | /* | ||
| 912 | * Returns 0 if all link frequencies used by the driver for the given number | ||
| 913 | * of MIPI data lanes are mentioned in the device tree, or the value of the | ||
| 914 | * first missing frequency otherwise. | ||
| 915 | */ | ||
| 916 | static s64 imx290_check_link_freqs(const struct imx290 *imx290, | ||
| 917 | const struct v4l2_fwnode_endpoint *ep) | ||
| 918 | { | ||
| 919 | int i, j; | ||
| 920 | const s64 *freqs = imx290_link_freqs_ptr(imx290); | ||
| 921 | int freqs_count = imx290_link_freqs_num(imx290); | ||
| 922 | |||
| 923 | for (i = 0; i < freqs_count; i++) { | ||
| 924 | for (j = 0; j < ep->nr_of_link_frequencies; j++) | ||
| 925 | if (freqs[i] == ep->link_frequencies[j]) | ||
| 926 | break; | ||
| 927 | if (j == ep->nr_of_link_frequencies) | ||
| 928 | return freqs[i]; | ||
| 929 | } | ||
| 930 | return 0; | ||
| 931 | } | ||
| 932 | |||
| 674 | static int imx290_probe(struct i2c_client *client) | 933 | static int imx290_probe(struct i2c_client *client) |
| 675 | { | 934 | { |
| 676 | struct device *dev = &client->dev; | 935 | struct device *dev = &client->dev; |
| 677 | struct fwnode_handle *endpoint; | 936 | struct fwnode_handle *endpoint; |
| 937 | /* Only CSI2 is supported for now: */ | ||
| 938 | struct v4l2_fwnode_endpoint ep = { | ||
| 939 | .bus_type = V4L2_MBUS_CSI2_DPHY | ||
| 940 | }; | ||
| 678 | struct imx290 *imx290; | 941 | struct imx290 *imx290; |
| 679 | u32 xclk_freq; | 942 | u32 xclk_freq; |
| 943 | s64 fq; | ||
| 680 | int ret; | 944 | int ret; |
| 681 | 945 | ||
| 682 | imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); | 946 | imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); |
| @@ -696,35 +960,40 @@ static int imx290_probe(struct i2c_client *client) · 13 unmodified lines | |||
| 696 | return -EINVAL; | 960 | return -EINVAL; |
| 697 | } | 961 | } |
| 698 | 962 | ||
| 699 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &imx290->ep); | 963 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); |
| 700 | fwnode_handle_put(endpoint); | 964 | fwnode_handle_put(endpoint); |
| 701 | if (ret) { | 965 | if (ret == -ENXIO) { |
| 966 | dev_err(dev, "Unsupported bus type, should be CSI2\n"); | ||
| 967 | goto free_err; | ||
| 968 | } else if (ret) { | ||
| 702 | dev_err(dev, "Parsing endpoint node failed\n"); | 969 | dev_err(dev, "Parsing endpoint node failed\n"); |
| 703 | goto free_err; | 970 | goto free_err; |
| 704 | } | 971 | } |
| 705 | 972 | ||
| 706 | if (!imx290->ep.nr_of_link_frequencies) { | 973 | /* Get number of data lanes */ |
| 707 | dev_err(dev, "link-frequency property not found in DT\n"); | 974 | imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes; |
| 975 | if (imx290->nlanes != 2 && imx290->nlanes != 4) { | ||
| 976 | dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes); | ||
| 708 | ret = -EINVAL; | 977 | ret = -EINVAL; |
| 709 | goto free_err; | 978 | goto free_err; |
| 710 | } | 979 | } |
| 711 | 980 | ||
| 712 | if (imx290->ep.link_frequencies[0] != IMX290_DEFAULT_LINK_FREQ) { | 981 | dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); |
| 713 | dev_err(dev, "Unsupported link frequency\n"); | 982 | |
| 983 | if (!ep.nr_of_link_frequencies) { | ||
| 984 | dev_err(dev, "link-frequency property not found in DT\n"); | ||
| 714 | ret = -EINVAL; | 985 | ret = -EINVAL; |
| 715 | goto free_err; | 986 | goto free_err; |
| 716 | } | 987 | } |
| 717 | 988 | ||
| 718 | /* Only CSI2 is supported for now */ | 989 | /* Check that link frequences for all the modes are in device tree */ |
| 719 | if (imx290->ep.bus_type != V4L2_MBUS_CSI2_DPHY) { | 990 | fq = imx290_check_link_freqs(imx290, &ep); |
| 720 | dev_err(dev, "Unsupported bus type, should be CSI2\n"); | 991 | if (fq) { |
| 992 | dev_err(dev, "Link frequency of %lld is not supported\n", fq); | ||
| 721 | ret = -EINVAL; | 993 | ret = -EINVAL; |
| 722 | goto free_err; | 994 | goto free_err; |
| 723 | } | 995 | } |
| 724 | 996 | ||
| 725 | /* Set default mode to max resolution */ | ||
| 726 | imx290->current_mode = &imx290_modes[0]; | ||
| 727 | |||
| 728 | /* get system clock (xclk) */ | 997 | /* get system clock (xclk) */ |
| 729 | imx290->xclk = devm_clk_get(dev, "xclk"); | 998 | imx290->xclk = devm_clk_get(dev, "xclk"); |
| 730 | if (IS_ERR(imx290->xclk)) { | 999 | if (IS_ERR(imx290->xclk)) { |
| @@ -760,7 +1029,8 @@ static int imx290_probe(struct i2c_client *client) · 29 unmodified lines | |||
| 760 | goto free_err; | 1029 | goto free_err; |
| 761 | } | 1030 | } |
| 762 | 1031 | ||
| 763 | imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); | 1032 | imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", |
| 1033 | GPIOD_OUT_HIGH); | ||
| 764 | if (IS_ERR(imx290->rst_gpio)) { | 1034 | if (IS_ERR(imx290->rst_gpio)) { |
| 765 | dev_err(dev, "Cannot get reset gpio\n"); | 1035 | dev_err(dev, "Cannot get reset gpio\n"); |
| 766 | ret = PTR_ERR(imx290->rst_gpio); | 1036 | ret = PTR_ERR(imx290->rst_gpio); |
| @@ -769,23 +1039,35 @@ static int imx290_probe(struct i2c_client *client) · 2 unmodified lines | |||
| 769 | 1039 | ||
| 770 | mutex_init(&imx290->lock); | 1040 | mutex_init(&imx290->lock); |
| 771 | 1041 | ||
| 772 | v4l2_ctrl_handler_init(&imx290->ctrls, 3); | 1042 | /* |
| 1043 | * Initialize the frame format. In particular, imx290->current_mode | ||
| 1044 | * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call | ||
| 1045 | * below relies on these fields. | ||
| 1046 | */ | ||
| 1047 | imx290_entity_init_cfg(&imx290->sd, NULL); | ||
| 1048 | |||
| 1049 | v4l2_ctrl_handler_init(&imx290->ctrls, 4); | ||
| 773 | 1050 | ||
| 774 | v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, | 1051 | v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, |
| 775 | V4L2_CID_GAIN, 0, 72, 1, 0); | 1052 | V4L2_CID_GAIN, 0, 72, 1, 0); |
| 1053 | |||
| 776 | imx290->link_freq = | 1054 | imx290->link_freq = |
| 777 | v4l2_ctrl_new_int_menu(&imx290->ctrls, | 1055 | v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, |
| 778 | &imx290_ctrl_ops, | ||
| 779 | V4L2_CID_LINK_FREQ, | 1056 | V4L2_CID_LINK_FREQ, |
| 780 | ARRAY_SIZE(imx290_link_freq) - 1, | 1057 | imx290_link_freqs_num(imx290) - 1, 0, |
| 781 | 0, imx290_link_freq); | 1058 | imx290_link_freqs_ptr(imx290)); |
| 782 | if (imx290->link_freq) | 1059 | if (imx290->link_freq) |
| 783 | imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 1060 | imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
| 784 | 1061 | ||
| 785 | imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, | 1062 | imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, |
| 786 | V4L2_CID_PIXEL_RATE, 1, | 1063 | V4L2_CID_PIXEL_RATE, |
| 787 | INT_MAX, 1, | 1064 | 1, INT_MAX, 1, |
| 788 | imx290_modes[0].pixel_rate); | 1065 | imx290_calc_pixel_rate(imx290)); |
| 1066 | |||
| 1067 | v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, | ||
| 1068 | V4L2_CID_TEST_PATTERN, | ||
| 1069 | ARRAY_SIZE(imx290_test_pattern_menu) - 1, | ||
| 1070 | 0, 0, imx290_test_pattern_menu); | ||
| 789 | 1071 | ||
| 790 | imx290->sd.ctrl_handler = &imx290->ctrls; | 1072 | imx290->sd.ctrl_handler = &imx290->ctrls; |
| 791 | 1073 | ||
| @@ -826,7 +1108,7 @@ static int imx290_probe(struct i2c_client *client) · 34 unmodified lines | |||
| 826 | pm_runtime_enable(dev); | 1108 | pm_runtime_enable(dev); |
| 827 | pm_runtime_idle(dev); | 1109 | pm_runtime_idle(dev); |
| 828 | 1110 | ||
| 829 | v4l2_fwnode_endpoint_free(&imx290->ep); | 1111 | v4l2_fwnode_endpoint_free(&ep); |
| 830 | 1112 | ||
| 831 | return 0; | 1113 | return 0; |
| 832 | 1114 | ||
| @@ -836,7 +1118,7 @@ free_ctrl: · 3 unmodified lines | |||
| 836 | v4l2_ctrl_handler_free(&imx290->ctrls); | 1118 | v4l2_ctrl_handler_free(&imx290->ctrls); |
| 837 | mutex_destroy(&imx290->lock); | 1119 | mutex_destroy(&imx290->lock); |
| 838 | free_err: | 1120 | free_err: |
| 839 | v4l2_fwnode_endpoint_free(&imx290->ep); | 1121 | v4l2_fwnode_endpoint_free(&ep); |
| 840 | 1122 | ||
| 841 | return ret; | 1123 | return ret; |
| 842 | } | 1124 | } |
| @@ -0,0 +1,341 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2017-2020 Jacopo Mondi | ||
| 4 | * Copyright (C) 2017-2020 Kieran Bingham | ||
| 5 | * Copyright (C) 2017-2020 Laurent Pinchart | ||
| 6 | * Copyright (C) 2017-2020 Niklas Söderlund | ||
| 7 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
| 8 | * Copyright (C) 2015 Cogent Embedded, Inc. | ||
| 9 | * | ||
| 10 | * This file exports functions to control the Maxim MAX9271 GMSL serializer | ||
| 11 | * chip. This is not a self-contained driver, as MAX9271 is usually embedded in | ||
| 12 | * camera modules with at least one image sensor and optional additional | ||
| 13 | * components, such as uController units or ISPs/DSPs. | ||
| 14 | * | ||
| 15 | * Drivers for the camera modules (i.e. rdacm20/21) are expected to use | ||
| 16 | * functions exported from this library driver to maximize code re-use. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/delay.h> | ||
| 20 | #include <linux/i2c.h> | ||
| 21 | |||
| 22 | #include "max9271.h" | ||
| 23 | |||
| 24 | static int max9271_read(struct max9271_device *dev, u8 reg) | ||
| 25 | { | ||
| 26 | int ret; | ||
| 27 | |||
| 28 | dev_dbg(&dev->client->dev, "%s(0x%02x)\n", __func__, reg); | ||
| 29 | |||
| 30 | ret = i2c_smbus_read_byte_data(dev->client, reg); | ||
| 31 | if (ret < 0) | ||
| 32 | dev_dbg(&dev->client->dev, | ||
| 33 | "%s: register 0x%02x read failed (%d)\n", | ||
| 34 | __func__, reg, ret); | ||
| 35 | |||
| 36 | return ret; | ||
| 37 | } | ||
| 38 | |||
| 39 | static int max9271_write(struct max9271_device *dev, u8 reg, u8 val) | ||
| 40 | { | ||
| 41 | int ret; | ||
| 42 | |||
| 43 | dev_dbg(&dev->client->dev, "%s(0x%02x, 0x%02x)\n", __func__, reg, val); | ||
| 44 | |||
| 45 | ret = i2c_smbus_write_byte_data(dev->client, reg, val); | ||
| 46 | if (ret < 0) | ||
| 47 | dev_err(&dev->client->dev, | ||
| 48 | "%s: register 0x%02x write failed (%d)\n", | ||
| 49 | __func__, reg, ret); | ||
| 50 | |||
| 51 | return ret; | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * max9271_pclk_detect() - Detect valid pixel clock from image sensor | ||
| 56 | * | ||
| 57 | * Wait up to 10ms for a valid pixel clock. | ||
| 58 | * | ||
| 59 | * Returns 0 for success, < 0 for pixel clock not properly detected | ||
| 60 | */ | ||
| 61 | static int max9271_pclk_detect(struct max9271_device *dev) | ||
| 62 | { | ||
| 63 | unsigned int i; | ||
| 64 | int ret; | ||
| 65 | |||
| 66 | for (i = 0; i < 100; i++) { | ||
| 67 | ret = max9271_read(dev, 0x15); | ||
| 68 | if (ret < 0) | ||
| 69 | return ret; | ||
| 70 | |||
| 71 | if (ret & MAX9271_PCLKDET) | ||
| 72 | return 0; | ||
| 73 | |||
| 74 | usleep_range(50, 100); | ||
| 75 | } | ||
| 76 | |||
| 77 | dev_err(&dev->client->dev, "Unable to detect valid pixel clock\n"); | ||
| 78 | |||
| 79 | return -EIO; | ||
| 80 | } | ||
| 81 | |||
| 82 | int max9271_set_serial_link(struct max9271_device *dev, bool enable) | ||
| 83 | { | ||
| 84 | int ret; | ||
| 85 | u8 val = MAX9271_REVCCEN | MAX9271_FWDCCEN; | ||
| 86 | |||
| 87 | if (enable) { | ||
| 88 | ret = max9271_pclk_detect(dev); | ||
| 89 | if (ret) | ||
| 90 | return ret; | ||
| 91 | |||
| 92 | val |= MAX9271_SEREN; | ||
| 93 | } else { | ||
| 94 | val |= MAX9271_CLINKEN; | ||
| 95 | } | ||
| 96 | |||
| 97 | /* | ||
| 98 | * The serializer temporarily disables the reverse control channel for | ||
| 99 | * 350µs after starting/stopping the forward serial link, but the | ||
| 100 | * deserializer synchronization time isn't clearly documented. | ||
| 101 | * | ||
| 102 | * According to the serializer datasheet we should wait 3ms, while | ||
| 103 | * according to the deserializer datasheet we should wait 5ms. | ||
| 104 | * | ||
| 105 | * Short delays here appear to show bit-errors in the writes following. | ||
| 106 | * Therefore a conservative delay seems best here. | ||
| 107 | */ | ||
| 108 | max9271_write(dev, 0x04, val); | ||
| 109 | usleep_range(5000, 8000); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | EXPORT_SYMBOL_GPL(max9271_set_serial_link); | ||
| 114 | |||
| 115 | int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config) | ||
| 116 | { | ||
| 117 | int ret; | ||
| 118 | |||
| 119 | ret = max9271_write(dev, 0x0d, i2c_config); | ||
| 120 | if (ret) | ||
| 121 | return ret; | ||
| 122 | |||
| 123 | /* The delay required after an I2C bus configuration change is not | ||
| 124 | * characterized in the serializer manual. Sleep up to 5msec to | ||
| 125 | * stay safe. | ||
| 126 | */ | ||
| 127 | usleep_range(3500, 5000); | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL_GPL(max9271_configure_i2c); | ||
| 132 | |||
| 133 | int max9271_set_high_threshold(struct max9271_device *dev, bool enable) | ||
| 134 | { | ||
| 135 | int ret; | ||
| 136 | |||
| 137 | ret = max9271_read(dev, 0x08); | ||
| 138 | if (ret < 0) | ||
| 139 | return ret; | ||
| 140 | |||
| 141 | /* | ||
| 142 | * Enable or disable reverse channel high threshold to increase | ||
| 143 | * immunity to power supply noise. | ||
| 144 | */ | ||
| 145 | max9271_write(dev, 0x08, enable ? ret | BIT(0) : ret & ~BIT(0)); | ||
| 146 | usleep_range(2000, 2500); | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | EXPORT_SYMBOL_GPL(max9271_set_high_threshold); | ||
| 151 | |||
| 152 | int max9271_configure_gmsl_link(struct max9271_device *dev) | ||
| 153 | { | ||
| 154 | /* | ||
| 155 | * Configure the GMSL link: | ||
| 156 | * | ||
| 157 | * - Double input mode, high data rate, 24-bit mode | ||
| 158 | * - Latch input data on PCLKIN rising edge | ||
| 159 | * - Enable HS/VS encoding | ||
| 160 | * - 1-bit parity error detection | ||
| 161 | * | ||
| 162 | * TODO: Make the GMSL link configuration parametric. | ||
| 163 | */ | ||
| 164 | max9271_write(dev, 0x07, MAX9271_DBL | MAX9271_HVEN | | ||
| 165 | MAX9271_EDC_1BIT_PARITY); | ||
| 166 | usleep_range(5000, 8000); | ||
| 167 | |||
| 168 | /* | ||
| 169 | * Adjust spread spectrum to +4% and auto-detect pixel clock | ||
| 170 | * and serial link rate. | ||
| 171 | */ | ||
| 172 | max9271_write(dev, 0x02, MAX9271_SPREAD_SPECT_4 | MAX9271_R02_RES | | ||
| 173 | MAX9271_PCLK_AUTODETECT | MAX9271_SERIAL_AUTODETECT); | ||
| 174 | usleep_range(5000, 8000); | ||
| 175 | |||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | EXPORT_SYMBOL_GPL(max9271_configure_gmsl_link); | ||
| 179 | |||
| 180 | int max9271_set_gpios(struct max9271_device *dev, u8 gpio_mask) | ||
| 181 | { | ||
| 182 | int ret; | ||
| 183 | |||
| 184 | ret = max9271_read(dev, 0x0f); | ||
| 185 | if (ret < 0) | ||
| 186 | return 0; | ||
| 187 | |||
| 188 | ret |= gpio_mask; | ||
| 189 | ret = max9271_write(dev, 0x0f, ret); | ||
| 190 | if (ret < 0) { | ||
| 191 | dev_err(&dev->client->dev, "Failed to set gpio (%d)\n", ret); | ||
| 192 | return ret; | ||
| 193 | } | ||
| 194 | |||
| 195 | usleep_range(3500, 5000); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | EXPORT_SYMBOL_GPL(max9271_set_gpios); | ||
| 200 | |||
| 201 | int max9271_clear_gpios(struct max9271_device *dev, u8 gpio_mask) | ||
| 202 | { | ||
| 203 | int ret; | ||
| 204 | |||
| 205 | ret = max9271_read(dev, 0x0f); | ||
| 206 | if (ret < 0) | ||
| 207 | return 0; | ||
| 208 | |||
| 209 | ret &= ~gpio_mask; | ||
| 210 | ret = max9271_write(dev, 0x0f, ret); | ||
| 211 | if (ret < 0) { | ||
| 212 | dev_err(&dev->client->dev, "Failed to clear gpio (%d)\n", ret); | ||
| 213 | return ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | usleep_range(3500, 5000); | ||
| 217 | |||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | EXPORT_SYMBOL_GPL(max9271_clear_gpios); | ||
| 221 | |||
| 222 | int max9271_enable_gpios(struct max9271_device *dev, u8 gpio_mask) | ||
| 223 | { | ||
| 224 | int ret; | ||
| 225 | |||
| 226 | ret = max9271_read(dev, 0x0f); | ||
| 227 | if (ret < 0) | ||
| 228 | return 0; | ||
| 229 | |||
| 230 | /* BIT(0) reserved: GPO is always enabled. */ | ||
| 231 | ret |= gpio_mask | BIT(0); | ||
| 232 | ret = max9271_write(dev, 0x0e, ret); | ||
| 233 | if (ret < 0) { | ||
| 234 | dev_err(&dev->client->dev, "Failed to enable gpio (%d)\n", ret); | ||
| 235 | return ret; | ||
| 236 | } | ||
| 237 | |||
| 238 | usleep_range(3500, 5000); | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | EXPORT_SYMBOL_GPL(max9271_enable_gpios); | ||
| 243 | |||
| 244 | int max9271_disable_gpios(struct max9271_device *dev, u8 gpio_mask) | ||
| 245 | { | ||
| 246 | int ret; | ||
| 247 | |||
| 248 | ret = max9271_read(dev, 0x0f); | ||
| 249 | if (ret < 0) | ||
| 250 | return 0; | ||
| 251 | |||
| 252 | /* BIT(0) reserved: GPO cannot be disabled */ | ||
| 253 | ret &= (~gpio_mask | BIT(0)); | ||
| 254 | ret = max9271_write(dev, 0x0e, ret); | ||
| 255 | if (ret < 0) { | ||
| 256 | dev_err(&dev->client->dev, "Failed to disable gpio (%d)\n", ret); | ||
| 257 | return ret; | ||
| 258 | } | ||
| 259 | |||
| 260 | usleep_range(3500, 5000); | ||
| 261 | |||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | EXPORT_SYMBOL_GPL(max9271_disable_gpios); | ||
| 265 | |||
| 266 | int max9271_verify_id(struct max9271_device *dev) | ||
| 267 | { | ||
| 268 | int ret; | ||
| 269 | |||
| 270 | ret = max9271_read(dev, 0x1e); | ||
| 271 | if (ret < 0) { | ||
| 272 | dev_err(&dev->client->dev, "MAX9271 ID read failed (%d)\n", | ||
| 273 | ret); | ||
| 274 | return ret; | ||
| 275 | } | ||
| 276 | |||
| 277 | if (ret != MAX9271_ID) { | ||
| 278 | dev_err(&dev->client->dev, "MAX9271 ID mismatch (0x%02x)\n", | ||
| 279 | ret); | ||
| 280 | return -ENXIO; | ||
| 281 | } | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | EXPORT_SYMBOL_GPL(max9271_verify_id); | ||
| 286 | |||
| 287 | int max9271_set_address(struct max9271_device *dev, u8 addr) | ||
| 288 | { | ||
| 289 | int ret; | ||
| 290 | |||
| 291 | ret = max9271_write(dev, 0x00, addr << 1); | ||
| 292 | if (ret < 0) { | ||
| 293 | dev_err(&dev->client->dev, | ||
| 294 | "MAX9271 I2C address change failed (%d)\n", ret); | ||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | usleep_range(3500, 5000); | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | EXPORT_SYMBOL_GPL(max9271_set_address); | ||
| 302 | |||
| 303 | int max9271_set_deserializer_address(struct max9271_device *dev, u8 addr) | ||
| 304 | { | ||
| 305 | int ret; | ||
| 306 | |||
| 307 | ret = max9271_write(dev, 0x01, addr << 1); | ||
| 308 | if (ret < 0) { | ||
| 309 | dev_err(&dev->client->dev, | ||
| 310 | "MAX9271 deserializer address set failed (%d)\n", ret); | ||
| 311 | return ret; | ||
| 312 | } | ||
| 313 | usleep_range(3500, 5000); | ||
| 314 | |||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | EXPORT_SYMBOL_GPL(max9271_set_deserializer_address); | ||
| 318 | |||
| 319 | int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest) | ||
| 320 | { | ||
| 321 | int ret; | ||
| 322 | |||
| 323 | ret = max9271_write(dev, 0x09, source << 1); | ||
| 324 | if (ret < 0) { | ||
| 325 | dev_err(&dev->client->dev, | ||
| 326 | "MAX9271 I2C translation setup failed (%d)\n", ret); | ||
| 327 | return ret; | ||
| 328 | } | ||
| 329 | usleep_range(3500, 5000); | ||
| 330 | |||
| 331 | ret = max9271_write(dev, 0x0a, dest << 1); | ||
| 332 | if (ret < 0) { | ||
| 333 | dev_err(&dev->client->dev, | ||
| 334 | "MAX9271 I2C translation setup failed (%d)\n", ret); | ||
| 335 | return ret; | ||
| 336 | } | ||
| 337 | usleep_range(3500, 5000); | ||
| 338 | |||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | EXPORT_SYMBOL_GPL(max9271_set_translation); | ||
| @@ -0,0 +1,224 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2017-2020 Jacopo Mondi | ||
| 4 | * Copyright (C) 2017-2020 Kieran Bingham | ||
| 5 | * Copyright (C) 2017-2020 Laurent Pinchart | ||
| 6 | * Copyright (C) 2017-2020 Niklas Söderlund | ||
| 7 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
| 8 | * Copyright (C) 2015 Cogent Embedded, Inc. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/i2c.h> | ||
| 12 | |||
| 13 | #define MAX9271_DEFAULT_ADDR 0x40 | ||
| 14 | |||
| 15 | /* Register 0x02 */ | ||
| 16 | #define MAX9271_SPREAD_SPECT_0 (0 << 5) | ||
| 17 | #define MAX9271_SPREAD_SPECT_05 (1 << 5) | ||
| 18 | #define MAX9271_SPREAD_SPECT_15 (2 << 5) | ||
| 19 | #define MAX9271_SPREAD_SPECT_1 (5 << 5) | ||
| 20 | #define MAX9271_SPREAD_SPECT_2 (3 << 5) | ||
| 21 | #define MAX9271_SPREAD_SPECT_3 (6 << 5) | ||
| 22 | #define MAX9271_SPREAD_SPECT_4 (7 << 5) | ||
| 23 | #define MAX9271_R02_RES BIT(4) | ||
| 24 | #define MAX9271_PCLK_AUTODETECT (3 << 2) | ||
| 25 | #define MAX9271_SERIAL_AUTODETECT (0x03) | ||
| 26 | /* Register 0x04 */ | ||
| 27 | #define MAX9271_SEREN BIT(7) | ||
| 28 | #define MAX9271_CLINKEN BIT(6) | ||
| 29 | #define MAX9271_PRBSEN BIT(5) | ||
| 30 | #define MAX9271_SLEEP BIT(4) | ||
| 31 | #define MAX9271_INTTYPE_I2C (0 << 2) | ||
| 32 | #define MAX9271_INTTYPE_UART (1 << 2) | ||
| 33 | #define MAX9271_INTTYPE_NONE (2 << 2) | ||
| 34 | #define MAX9271_REVCCEN BIT(1) | ||
| 35 | #define MAX9271_FWDCCEN BIT(0) | ||
| 36 | /* Register 0x07 */ | ||
| 37 | #define MAX9271_DBL BIT(7) | ||
| 38 | #define MAX9271_DRS BIT(6) | ||
| 39 | #define MAX9271_BWS BIT(5) | ||
| 40 | #define MAX9271_ES BIT(4) | ||
| 41 | #define MAX9271_HVEN BIT(2) | ||
| 42 | #define MAX9271_EDC_1BIT_PARITY (0 << 0) | ||
| 43 | #define MAX9271_EDC_6BIT_CRC (1 << 0) | ||
| 44 | #define MAX9271_EDC_6BIT_HAMMING (2 << 0) | ||
| 45 | /* Register 0x08 */ | ||
| 46 | #define MAX9271_INVVS BIT(7) | ||
| 47 | #define MAX9271_INVHS BIT(6) | ||
| 48 | #define MAX9271_REV_LOGAIN BIT(3) | ||
| 49 | #define MAX9271_REV_HIVTH BIT(0) | ||
| 50 | /* Register 0x09 */ | ||
| 51 | #define MAX9271_ID 0x09 | ||
| 52 | /* Register 0x0d */ | ||
| 53 | #define MAX9271_I2CLOCACK BIT(7) | ||
| 54 | #define MAX9271_I2CSLVSH_1046NS_469NS (3 << 5) | ||
| 55 | #define MAX9271_I2CSLVSH_938NS_352NS (2 << 5) | ||
| 56 | #define MAX9271_I2CSLVSH_469NS_234NS (1 << 5) | ||
| 57 | #define MAX9271_I2CSLVSH_352NS_117NS (0 << 5) | ||
| 58 | #define MAX9271_I2CMSTBT_837KBPS (7 << 2) | ||
| 59 | #define MAX9271_I2CMSTBT_533KBPS (6 << 2) | ||
| 60 | #define MAX9271_I2CMSTBT_339KBPS (5 << 2) | ||
| 61 | #define MAX9271_I2CMSTBT_173KBPS (4 << 2) | ||
| 62 | #define MAX9271_I2CMSTBT_105KBPS (3 << 2) | ||
| 63 | #define MAX9271_I2CMSTBT_84KBPS (2 << 2) | ||
| 64 | #define MAX9271_I2CMSTBT_28KBPS (1 << 2) | ||
| 65 | #define MAX9271_I2CMSTBT_8KBPS (0 << 2) | ||
| 66 | #define MAX9271_I2CSLVTO_NONE (3 << 0) | ||
| 67 | #define MAX9271_I2CSLVTO_1024US (2 << 0) | ||
| 68 | #define MAX9271_I2CSLVTO_256US (1 << 0) | ||
| 69 | #define MAX9271_I2CSLVTO_64US (0 << 0) | ||
| 70 | /* Register 0x0f */ | ||
| 71 | #define MAX9271_GPIO5OUT BIT(5) | ||
| 72 | #define MAX9271_GPIO4OUT BIT(4) | ||
| 73 | #define MAX9271_GPIO3OUT BIT(3) | ||
| 74 | #define MAX9271_GPIO2OUT BIT(2) | ||
| 75 | #define MAX9271_GPIO1OUT BIT(1) | ||
| 76 | #define MAX9271_GPO BIT(0) | ||
| 77 | /* Register 0x15 */ | ||
| 78 | #define MAX9271_PCLKDET BIT(0) | ||
| 79 | |||
| 80 | /** | ||
| 81 | * struct max9271_device - max9271 device | ||
| 82 | * @client: The i2c client for the max9271 instance | ||
| 83 | */ | ||
| 84 | struct max9271_device { | ||
| 85 | struct i2c_client *client; | ||
| 86 | }; | ||
| 87 | |||
| 88 | /** | ||
| 89 | * max9271_set_serial_link() - Enable/disable serial link | ||
| 90 | * @dev: The max9271 device | ||
| 91 | * @enable: Serial link enable/disable flag | ||
| 92 | * | ||
| 93 | * Return 0 on success or a negative error code on failure | ||
| 94 | */ | ||
| 95 | int max9271_set_serial_link(struct max9271_device *dev, bool enable); | ||
| 96 | |||
| 97 | /** | ||
| 98 | * max9271_configure_i2c() - Configure I2C bus parameters | ||
| 99 | * @dev: The max9271 device | ||
| 100 | * @i2c_config: The I2C bus configuration bit mask | ||
| 101 | * | ||
| 102 | * Configure MAX9271 I2C interface. The bus configuration provided in the | ||
| 103 | * @i2c_config parameter shall be assembled using bit values defined by the | ||
| 104 | * MAX9271_I2C* macros. | ||
| 105 | * | ||
| 106 | * Return 0 on success or a negative error code on failure | ||
| 107 | */ | ||
| 108 | int max9271_configure_i2c(struct max9271_device *dev, u8 i2c_config); | ||
| 109 | |||
| 110 | /** | ||
| 111 | * max9271_set_high_threshold() - Enable or disable reverse channel high | ||
| 112 | * threshold | ||
| 113 | * @dev: The max9271 device | ||
| 114 | * @enable: High threshold enable/disable flag | ||
| 115 | * | ||
| 116 | * Return 0 on success or a negative error code on failure | ||
| 117 | */ | ||
| 118 | int max9271_set_high_threshold(struct max9271_device *dev, bool enable); | ||
| 119 | |||
| 120 | /** | ||
| 121 | * max9271_configure_gmsl_link() - Configure the GMSL link | ||
| 122 | * @dev: The max9271 device | ||
| 123 | * | ||
| 124 | * FIXME: the GMSL link configuration is currently hardcoded and performed | ||
| 125 | * by programming registers 0x04, 0x07 and 0x02. | ||
| 126 | * | ||
| 127 | * Return 0 on success or a negative error code on failure | ||
| 128 | */ | ||
| 129 | int max9271_configure_gmsl_link(struct max9271_device *dev); | ||
| 130 | |||
| 131 | /** | ||
| 132 | * max9271_set_gpios() - Set gpio lines to physical high value | ||
| 133 | * @dev: The max9271 device | ||
| 134 | * @gpio_mask: The mask of gpio lines to set to high value | ||
| 135 | * | ||
| 136 | * The @gpio_mask parameter shall be assembled using the MAX9271_GP[IO|O]* | ||
| 137 | * bit values. | ||
| 138 | * | ||
| 139 | * Return 0 on success or a negative error code on failure | ||
| 140 | */ | ||
| 141 | int max9271_set_gpios(struct max9271_device *dev, u8 gpio_mask); | ||
| 142 | |||
| 143 | /** | ||
| 144 | * max9271_clear_gpios() - Set gpio lines to physical low value | ||
| 145 | * @dev: The max9271 device | ||
| 146 | * @gpio_mask: The mask of gpio lines to set to low value | ||
| 147 | * | ||
| 148 | * The @gpio_mask parameter shall be assembled using the MAX9271_GP[IO|O]* | ||
| 149 | * bit values. | ||
| 150 | * | ||
| 151 | * Return 0 on success or a negative error code on failure | ||
| 152 | */ | ||
| 153 | int max9271_clear_gpios(struct max9271_device *dev, u8 gpio_mask); | ||
| 154 | |||
| 155 | /** | ||
| 156 | * max9271_enable_gpios() - Enable gpio lines | ||
| 157 | * @dev: The max9271 device | ||
| 158 | * @gpio_mask: The mask of gpio lines to enable | ||
| 159 | * | ||
| 160 | * The @gpio_mask parameter shall be assembled using the MAX9271_GPIO* | ||
| 161 | * bit values. GPO line is always enabled by default. | ||
| 162 | * | ||
| 163 | * Return 0 on success or a negative error code on failure | ||
| 164 | */ | ||
| 165 | int max9271_enable_gpios(struct max9271_device *dev, u8 gpio_mask); | ||
| 166 | |||
| 167 | /** | ||
| 168 | * max9271_disable_gpios() - Disable gpio lines | ||
| 169 | * @dev: The max9271 device | ||
| 170 | * @gpio_mask: The mask of gpio lines to disable | ||
| 171 | * | ||
| 172 | * The @gpio_mask parameter shall be assembled using the MAX9271_GPIO* | ||
| 173 | * bit values. GPO line is always enabled by default and cannot be disabled. | ||
| 174 | * | ||
| 175 | * Return 0 on success or a negative error code on failure | ||
| 176 | */ | ||
| 177 | int max9271_disable_gpios(struct max9271_device *dev, u8 gpio_mask); | ||
| 178 | |||
| 179 | /** | ||
| 180 | * max9271_verify_id() - Read and verify MAX9271 id | ||
| 181 | * @dev: The max9271 device | ||
| 182 | * | ||
| 183 | * Return 0 on success or a negative error code on failure | ||
| 184 | */ | ||
| 185 | int max9271_verify_id(struct max9271_device *dev); | ||
| 186 | |||
| 187 | /** | ||
| 188 | * max9271_set_address() - Program a new I2C address | ||
| 189 | * @dev: The max9271 device | ||
| 190 | * @addr: The new I2C address in 7-bit format | ||
| 191 | * | ||
| 192 | * This function only takes care of programming the new I2C address @addr to | ||
| 193 | * in the MAX9271 chip registers, it is responsiblity of the caller to set | ||
| 194 | * the i2c address client to the @addr value to be able to communicate with | ||
| 195 | * the MAX9271 chip using the I2C framework APIs after this function returns. | ||
| 196 | * | ||
| 197 | * Return 0 on success or a negative error code on failure | ||
| 198 | */ | ||
| 199 | int max9271_set_address(struct max9271_device *dev, u8 addr); | ||
| 200 | |||
| 201 | /** | ||
| 202 | * max9271_set_deserializer_address() - Program the remote deserializer address | ||
| 203 | * @dev: The max9271 device | ||
| 204 | * @addr: The deserializer I2C address in 7-bit format | ||
| 205 | * | ||
| 206 | * Return 0 on success or a negative error code on failure | ||
| 207 | */ | ||
| 208 | int max9271_set_deserializer_address(struct max9271_device *dev, u8 addr); | ||
| 209 | |||
| 210 | /** | ||
| 211 | * max9271_set_translation() - Program I2C address translation | ||
| 212 | * @dev: The max9271 device | ||
| 213 | * @source: The I2C source address | ||
| 214 | * @dest: The I2C destination address | ||
| 215 | * | ||
| 216 | * Program address translation from @source to @dest. This is required to | ||
| 217 | * communicate with local devices that do not support address reprogramming. | ||
| 218 | * | ||
| 219 | * TODO: The device supports translation of two address, this function currently | ||
| 220 | * supports a single one. | ||
| 221 | * | ||
| 222 | * Return 0 on success or a negative error code on failure | ||
| 223 | */ | ||
| 224 | int max9271_set_translation(struct max9271_device *dev, u8 source, u8 dest); | ||
| @@ -0,0 +1,1320 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Maxim MAX9286 GMSL Deserializer Driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017-2019 Jacopo Mondi | ||
| 6 | * Copyright (C) 2017-2019 Kieran Bingham | ||
| 7 | * Copyright (C) 2017-2019 Laurent Pinchart | ||
| 8 | * Copyright (C) 2017-2019 Niklas Söderlund | ||
| 9 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
| 10 | * Copyright (C) 2015 Cogent Embedded, Inc. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/delay.h> | ||
| 14 | #include <linux/device.h> | ||
| 15 | #include <linux/fwnode.h> | ||
| 16 | #include <linux/gpio/consumer.h> | ||
| 17 | #include <linux/gpio/driver.h> | ||
| 18 | #include <linux/i2c.h> | ||
| 19 | #include <linux/i2c-mux.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/mutex.h> | ||
| 22 | #include <linux/of_graph.h> | ||
| 23 | #include <linux/regulator/consumer.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | |||
| 26 | #include <media/v4l2-async.h> | ||
| 27 | #include <media/v4l2-ctrls.h> | ||
| 28 | #include <media/v4l2-device.h> | ||
| 29 | #include <media/v4l2-fwnode.h> | ||
| 30 | #include <media/v4l2-subdev.h> | ||
| 31 | |||
| 32 | /* Register 0x00 */ | ||
| 33 | #define MAX9286_MSTLINKSEL_AUTO (7 << 5) | ||
| 34 | #define MAX9286_MSTLINKSEL(n) ((n) << 5) | ||
| 35 | #define MAX9286_EN_VS_GEN BIT(4) | ||
| 36 | #define MAX9286_LINKEN(n) (1 << (n)) | ||
| 37 | /* Register 0x01 */ | ||
| 38 | #define MAX9286_FSYNCMODE_ECU (3 << 6) | ||
| 39 | #define MAX9286_FSYNCMODE_EXT (2 << 6) | ||
| 40 | #define MAX9286_FSYNCMODE_INT_OUT (1 << 6) | ||
| 41 | #define MAX9286_FSYNCMODE_INT_HIZ (0 << 6) | ||
| 42 | #define MAX9286_GPIEN BIT(5) | ||
| 43 | #define MAX9286_ENLMO_RSTFSYNC BIT(2) | ||
| 44 | #define MAX9286_FSYNCMETH_AUTO (2 << 0) | ||
| 45 | #define MAX9286_FSYNCMETH_SEMI_AUTO (1 << 0) | ||
| 46 | #define MAX9286_FSYNCMETH_MANUAL (0 << 0) | ||
| 47 | #define MAX9286_REG_FSYNC_PERIOD_L 0x06 | ||
| 48 | #define MAX9286_REG_FSYNC_PERIOD_M 0x07 | ||
| 49 | #define MAX9286_REG_FSYNC_PERIOD_H 0x08 | ||
| 50 | /* Register 0x0a */ | ||
| 51 | #define MAX9286_FWDCCEN(n) (1 << ((n) + 4)) | ||
| 52 | #define MAX9286_REVCCEN(n) (1 << (n)) | ||
| 53 | /* Register 0x0c */ | ||
| 54 | #define MAX9286_HVEN BIT(7) | ||
| 55 | #define MAX9286_EDC_6BIT_HAMMING (2 << 5) | ||
| 56 | #define MAX9286_EDC_6BIT_CRC (1 << 5) | ||
| 57 | #define MAX9286_EDC_1BIT_PARITY (0 << 5) | ||
| 58 | #define MAX9286_DESEL BIT(4) | ||
| 59 | #define MAX9286_INVVS BIT(3) | ||
| 60 | #define MAX9286_INVHS BIT(2) | ||
| 61 | #define MAX9286_HVSRC_D0 (2 << 0) | ||
| 62 | #define MAX9286_HVSRC_D14 (1 << 0) | ||
| 63 | #define MAX9286_HVSRC_D18 (0 << 0) | ||
| 64 | /* Register 0x0f */ | ||
| 65 | #define MAX9286_0X0F_RESERVED BIT(3) | ||
| 66 | /* Register 0x12 */ | ||
| 67 | #define MAX9286_CSILANECNT(n) (((n) - 1) << 6) | ||
| 68 | #define MAX9286_CSIDBL BIT(5) | ||
| 69 | #define MAX9286_DBL BIT(4) | ||
| 70 | #define MAX9286_DATATYPE_USER_8BIT (11 << 0) | ||
| 71 | #define MAX9286_DATATYPE_USER_YUV_12BIT (10 << 0) | ||
| 72 | #define MAX9286_DATATYPE_USER_24BIT (9 << 0) | ||
| 73 | #define MAX9286_DATATYPE_RAW14 (8 << 0) | ||
| 74 | #define MAX9286_DATATYPE_RAW11 (7 << 0) | ||
| 75 | #define MAX9286_DATATYPE_RAW10 (6 << 0) | ||
| 76 | #define MAX9286_DATATYPE_RAW8 (5 << 0) | ||
| 77 | #define MAX9286_DATATYPE_YUV422_10BIT (4 << 0) | ||
| 78 | #define MAX9286_DATATYPE_YUV422_8BIT (3 << 0) | ||
| 79 | #define MAX9286_DATATYPE_RGB555 (2 << 0) | ||
| 80 | #define MAX9286_DATATYPE_RGB565 (1 << 0) | ||
| 81 | #define MAX9286_DATATYPE_RGB888 (0 << 0) | ||
| 82 | /* Register 0x15 */ | ||
| 83 | #define MAX9286_VC(n) ((n) << 5) | ||
| 84 | #define MAX9286_VCTYPE BIT(4) | ||
| 85 | #define MAX9286_CSIOUTEN BIT(3) | ||
| 86 | #define MAX9286_0X15_RESV (3 << 0) | ||
| 87 | /* Register 0x1b */ | ||
| 88 | #define MAX9286_SWITCHIN(n) (1 << ((n) + 4)) | ||
| 89 | #define MAX9286_ENEQ(n) (1 << (n)) | ||
| 90 | /* Register 0x27 */ | ||
| 91 | #define MAX9286_LOCKED BIT(7) | ||
| 92 | /* Register 0x31 */ | ||
| 93 | #define MAX9286_FSYNC_LOCKED BIT(6) | ||
| 94 | /* Register 0x34 */ | ||
| 95 | #define MAX9286_I2CLOCACK BIT(7) | ||
| 96 | #define MAX9286_I2CSLVSH_1046NS_469NS (3 << 5) | ||
| 97 | #define MAX9286_I2CSLVSH_938NS_352NS (2 << 5) | ||
| 98 | #define MAX9286_I2CSLVSH_469NS_234NS (1 << 5) | ||
| 99 | #define MAX9286_I2CSLVSH_352NS_117NS (0 << 5) | ||
| 100 | #define MAX9286_I2CMSTBT_837KBPS (7 << 2) | ||
| 101 | #define MAX9286_I2CMSTBT_533KBPS (6 << 2) | ||
| 102 | #define MAX9286_I2CMSTBT_339KBPS (5 << 2) | ||
| 103 | #define MAX9286_I2CMSTBT_173KBPS (4 << 2) | ||
| 104 | #define MAX9286_I2CMSTBT_105KBPS (3 << 2) | ||
| 105 | #define MAX9286_I2CMSTBT_84KBPS (2 << 2) | ||
| 106 | #define MAX9286_I2CMSTBT_28KBPS (1 << 2) | ||
| 107 | #define MAX9286_I2CMSTBT_8KBPS (0 << 2) | ||
| 108 | #define MAX9286_I2CSLVTO_NONE (3 << 0) | ||
| 109 | #define MAX9286_I2CSLVTO_1024US (2 << 0) | ||
| 110 | #define MAX9286_I2CSLVTO_256US (1 << 0) | ||
| 111 | #define MAX9286_I2CSLVTO_64US (0 << 0) | ||
| 112 | /* Register 0x3b */ | ||
| 113 | #define MAX9286_REV_TRF(n) ((n) << 4) | ||
| 114 | #define MAX9286_REV_AMP(n) ((((n) - 30) / 10) << 1) /* in mV */ | ||
| 115 | #define MAX9286_REV_AMP_X BIT(0) | ||
| 116 | /* Register 0x3f */ | ||
| 117 | #define MAX9286_EN_REV_CFG BIT(6) | ||
| 118 | #define MAX9286_REV_FLEN(n) ((n) - 20) | ||
| 119 | /* Register 0x49 */ | ||
| 120 | #define MAX9286_VIDEO_DETECT_MASK 0x0f | ||
| 121 | /* Register 0x69 */ | ||
| 122 | #define MAX9286_LFLTBMONMASKED BIT(7) | ||
| 123 | #define MAX9286_LOCKMONMASKED BIT(6) | ||
| 124 | #define MAX9286_AUTOCOMBACKEN BIT(5) | ||
| 125 | #define MAX9286_AUTOMASKEN BIT(4) | ||
| 126 | #define MAX9286_MASKLINK(n) ((n) << 0) | ||
| 127 | |||
| 128 | /* | ||
| 129 | * The sink and source pads are created to match the OF graph port numbers so | ||
| 130 | * that their indexes can be used interchangeably. | ||
| 131 | */ | ||
| 132 | #define MAX9286_NUM_GMSL 4 | ||
| 133 | #define MAX9286_N_SINKS 4 | ||
| 134 | #define MAX9286_N_PADS 5 | ||
| 135 | #define MAX9286_SRC_PAD 4 | ||
| 136 | |||
| 137 | struct max9286_source { | ||
| 138 | struct v4l2_async_subdev asd; | ||
| 139 | struct v4l2_subdev *sd; | ||
| 140 | struct fwnode_handle *fwnode; | ||
| 141 | }; | ||
| 142 | |||
| 143 | #define asd_to_max9286_source(_asd) \ | ||
| 144 | container_of(_asd, struct max9286_source, asd) | ||
| 145 | |||
| 146 | struct max9286_priv { | ||
| 147 | struct i2c_client *client; | ||
| 148 | struct gpio_desc *gpiod_pwdn; | ||
| 149 | struct v4l2_subdev sd; | ||
| 150 | struct media_pad pads[MAX9286_N_PADS]; | ||
| 151 | struct regulator *regulator; | ||
| 152 | |||
| 153 | struct gpio_chip gpio; | ||
| 154 | u8 gpio_state; | ||
| 155 | |||
| 156 | struct i2c_mux_core *mux; | ||
| 157 | unsigned int mux_channel; | ||
| 158 | bool mux_open; | ||
| 159 | |||
| 160 | struct v4l2_ctrl_handler ctrls; | ||
| 161 | struct v4l2_ctrl *pixelrate; | ||
| 162 | |||
| 163 | struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS]; | ||
| 164 | |||
| 165 | /* Protects controls and fmt structures */ | ||
| 166 | struct mutex mutex; | ||
| 167 | |||
| 168 | unsigned int nsources; | ||
| 169 | unsigned int source_mask; | ||
| 170 | unsigned int route_mask; | ||
| 171 | unsigned int bound_sources; | ||
| 172 | unsigned int csi2_data_lanes; | ||
| 173 | struct max9286_source sources[MAX9286_NUM_GMSL]; | ||
| 174 | struct v4l2_async_notifier notifier; | ||
| 175 | }; | ||
| 176 | |||
| 177 | static struct max9286_source *next_source(struct max9286_priv *priv, | ||
| 178 | struct max9286_source *source) | ||
| 179 | { | ||
| 180 | if (!source) | ||
| 181 | source = &priv->sources[0]; | ||
| 182 | else | ||
| 183 | source++; | ||
| 184 | |||
| 185 | for (; source < &priv->sources[MAX9286_NUM_GMSL]; source++) { | ||
| 186 | if (source->fwnode) | ||
| 187 | return source; | ||
| 188 | } | ||
| 189 | |||
| 190 | return NULL; | ||
| 191 | } | ||
| 192 | |||
| 193 | #define for_each_source(priv, source) \ | ||
| 194 | for ((source) = NULL; ((source) = next_source((priv), (source))); ) | ||
| 195 | |||
| 196 | #define to_index(priv, source) ((source) - &(priv)->sources[0]) | ||
| 197 | |||
| 198 | static inline struct max9286_priv *sd_to_max9286(struct v4l2_subdev *sd) | ||
| 199 | { | ||
| 200 | return container_of(sd, struct max9286_priv, sd); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* ----------------------------------------------------------------------------- | ||
| 204 | * I2C IO | ||
| 205 | */ | ||
| 206 | |||
| 207 | static int max9286_read(struct max9286_priv *priv, u8 reg) | ||
| 208 | { | ||
| 209 | int ret; | ||
| 210 | |||
| 211 | ret = i2c_smbus_read_byte_data(priv->client, reg); | ||
| 212 | if (ret < 0) | ||
| 213 | dev_err(&priv->client->dev, | ||
| 214 | "%s: register 0x%02x read failed (%d)\n", | ||
| 215 | __func__, reg, ret); | ||
| 216 | |||
| 217 | return ret; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int max9286_write(struct max9286_priv *priv, u8 reg, u8 val) | ||
| 221 | { | ||
| 222 | int ret; | ||
| 223 | |||
| 224 | ret = i2c_smbus_write_byte_data(priv->client, reg, val); | ||
| 225 | if (ret < 0) | ||
| 226 | dev_err(&priv->client->dev, | ||
| 227 | "%s: register 0x%02x write failed (%d)\n", | ||
| 228 | __func__, reg, ret); | ||
| 229 | |||
| 230 | return ret; | ||
| 231 | } | ||
| 232 | |||
| 233 | /* ----------------------------------------------------------------------------- | ||
| 234 | * I2C Multiplexer | ||
| 235 | */ | ||
| 236 | |||
| 237 | static void max9286_i2c_mux_configure(struct max9286_priv *priv, u8 conf) | ||
| 238 | { | ||
| 239 | max9286_write(priv, 0x0a, conf); | ||
| 240 | |||
| 241 | /* | ||
| 242 | * We must sleep after any change to the forward or reverse channel | ||
| 243 | * configuration. | ||
| 244 | */ | ||
| 245 | usleep_range(3000, 5000); | ||
| 246 | } | ||
| 247 | |||
| 248 | static void max9286_i2c_mux_open(struct max9286_priv *priv) | ||
| 249 | { | ||
| 250 | /* Open all channels on the MAX9286 */ | ||
| 251 | max9286_i2c_mux_configure(priv, 0xff); | ||
| 252 | |||
| 253 | priv->mux_open = true; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void max9286_i2c_mux_close(struct max9286_priv *priv) | ||
| 257 | { | ||
| 258 | /* | ||
| 259 | * Ensure that both the forward and reverse channel are disabled on the | ||
| 260 | * mux, and that the channel ID is invalidated to ensure we reconfigure | ||
| 261 | * on the next max9286_i2c_mux_select() call. | ||
| 262 | */ | ||
| 263 | max9286_i2c_mux_configure(priv, 0x00); | ||
| 264 | |||
| 265 | priv->mux_open = false; | ||
| 266 | priv->mux_channel = -1; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int max9286_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) | ||
| 270 | { | ||
| 271 | struct max9286_priv *priv = i2c_mux_priv(muxc); | ||
| 272 | |||
| 273 | /* Channel select is disabled when configured in the opened state. */ | ||
| 274 | if (priv->mux_open) | ||
| 275 | return 0; | ||
| 276 | |||
| 277 | if (priv->mux_channel == chan) | ||
| 278 | return 0; | ||
| 279 | |||
| 280 | priv->mux_channel = chan; | ||
| 281 | |||
| 282 | max9286_i2c_mux_configure(priv, | ||
| 283 | MAX9286_FWDCCEN(chan) | | ||
| 284 | MAX9286_REVCCEN(chan)); | ||
| 285 | |||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static int max9286_i2c_mux_init(struct max9286_priv *priv) | ||
| 290 | { | ||
| 291 | struct max9286_source *source; | ||
| 292 | int ret; | ||
| 293 | |||
| 294 | if (!i2c_check_functionality(priv->client->adapter, | ||
| 295 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) | ||
| 296 | return -ENODEV; | ||
| 297 | |||
| 298 | priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev, | ||
| 299 | priv->nsources, 0, I2C_MUX_LOCKED, | ||
| 300 | max9286_i2c_mux_select, NULL); | ||
| 301 | if (!priv->mux) | ||
| 302 | return -ENOMEM; | ||
| 303 | |||
| 304 | priv->mux->priv = priv; | ||
| 305 | |||
| 306 | for_each_source(priv, source) { | ||
| 307 | unsigned int index = to_index(priv, source); | ||
| 308 | |||
| 309 | ret = i2c_mux_add_adapter(priv->mux, 0, index, 0); | ||
| 310 | if (ret < 0) | ||
| 311 | goto error; | ||
| 312 | } | ||
| 313 | |||
| 314 | return 0; | ||
| 315 | |||
| 316 | error: | ||
| 317 | i2c_mux_del_adapters(priv->mux); | ||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | static void max9286_configure_i2c(struct max9286_priv *priv, bool localack) | ||
| 322 | { | ||
| 323 | u8 config = MAX9286_I2CSLVSH_469NS_234NS | MAX9286_I2CSLVTO_1024US | | ||
| 324 | MAX9286_I2CMSTBT_105KBPS; | ||
| 325 | |||
| 326 | if (localack) | ||
| 327 | config |= MAX9286_I2CLOCACK; | ||
| 328 | |||
| 329 | max9286_write(priv, 0x34, config); | ||
| 330 | usleep_range(3000, 5000); | ||
| 331 | } | ||
| 332 | |||
| 333 | /* | ||
| 334 | * max9286_check_video_links() - Make sure video links are detected and locked | ||
| 335 | * | ||
| 336 | * Performs safety checks on video link status. Make sure they are detected | ||
| 337 | * and all enabled links are locked. | ||
| 338 | * | ||
| 339 | * Returns 0 for success, -EIO for errors. | ||
| 340 | */ | ||
| 341 | static int max9286_check_video_links(struct max9286_priv *priv) | ||
| 342 | { | ||
| 343 | unsigned int i; | ||
| 344 | int ret; | ||
| 345 | |||
| 346 | /* | ||
| 347 | * Make sure valid video links are detected. | ||
| 348 | * The delay is not characterized in de-serializer manual, wait up | ||
| 349 | * to 5 ms. | ||
| 350 | */ | ||
| 351 | for (i = 0; i < 10; i++) { | ||
| 352 | ret = max9286_read(priv, 0x49); | ||
| 353 | if (ret < 0) | ||
| 354 | return -EIO; | ||
| 355 | |||
| 356 | if ((ret & MAX9286_VIDEO_DETECT_MASK) == priv->source_mask) | ||
| 357 | break; | ||
| 358 | |||
| 359 | usleep_range(350, 500); | ||
| 360 | } | ||
| 361 | |||
| 362 | if (i == 10) { | ||
| 363 | dev_err(&priv->client->dev, | ||
| 364 | "Unable to detect video links: 0x%02x\n", ret); | ||
| 365 | return -EIO; | ||
| 366 | } | ||
| 367 | |||
| 368 | /* Make sure all enabled links are locked (4ms max). */ | ||
| 369 | for (i = 0; i < 10; i++) { | ||
| 370 | ret = max9286_read(priv, 0x27); | ||
| 371 | if (ret < 0) | ||
| 372 | return -EIO; | ||
| 373 | |||
| 374 | if (ret & MAX9286_LOCKED) | ||
| 375 | break; | ||
| 376 | |||
| 377 | usleep_range(350, 450); | ||
| 378 | } | ||
| 379 | |||
| 380 | if (i == 10) { | ||
| 381 | dev_err(&priv->client->dev, "Not all enabled links locked\n"); | ||
| 382 | return -EIO; | ||
| 383 | } | ||
| 384 | |||
| 385 | return 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* | ||
| 389 | * max9286_check_config_link() - Detect and wait for configuration links | ||
| 390 | * | ||
| 391 | * Determine if the configuration channel is up and settled for a link. | ||
| 392 | * | ||
| 393 | * Returns 0 for success, -EIO for errors. | ||
| 394 | */ | ||
| 395 | static int max9286_check_config_link(struct max9286_priv *priv, | ||
| 396 | unsigned int source_mask) | ||
| 397 | { | ||
| 398 | unsigned int conflink_mask = (source_mask & 0x0f) << 4; | ||
| 399 | unsigned int i; | ||
| 400 | int ret; | ||
| 401 | |||
| 402 | /* | ||
| 403 | * Make sure requested configuration links are detected. | ||
| 404 | * The delay is not characterized in the chip manual: wait up | ||
| 405 | * to 5 milliseconds. | ||
| 406 | */ | ||
| 407 | for (i = 0; i < 10; i++) { | ||
| 408 | ret = max9286_read(priv, 0x49) & 0xf0; | ||
| 409 | if (ret < 0) | ||
| 410 | return -EIO; | ||
| 411 | |||
| 412 | if (ret == conflink_mask) | ||
| 413 | break; | ||
| 414 | |||
| 415 | usleep_range(350, 500); | ||
| 416 | } | ||
| 417 | |||
| 418 | if (ret != conflink_mask) { | ||
| 419 | dev_err(&priv->client->dev, | ||
| 420 | "Unable to detect configuration links: 0x%02x expected 0x%02x\n", | ||
| 421 | ret, conflink_mask); | ||
| 422 | return -EIO; | ||
| 423 | } | ||
| 424 | |||
| 425 | dev_info(&priv->client->dev, | ||
| 426 | "Successfully detected configuration links after %u loops: 0x%02x\n", | ||
| 427 | i, conflink_mask); | ||
| 428 | |||
| 429 | return 0; | ||
| 430 | } | ||
| 431 | |||
| 432 | /* ----------------------------------------------------------------------------- | ||
| 433 | * V4L2 Subdev | ||
| 434 | */ | ||
| 435 | |||
| 436 | static int max9286_set_pixelrate(struct max9286_priv *priv) | ||
| 437 | { | ||
| 438 | struct max9286_source *source = NULL; | ||
| 439 | u64 pixelrate = 0; | ||
| 440 | |||
| 441 | for_each_source(priv, source) { | ||
| 442 | struct v4l2_ctrl *ctrl; | ||
| 443 | u64 source_rate = 0; | ||
| 444 | |||
| 445 | /* Pixel rate is mandatory to be reported by sources. */ | ||
| 446 | ctrl = v4l2_ctrl_find(source->sd->ctrl_handler, | ||
| 447 | V4L2_CID_PIXEL_RATE); | ||
| 448 | if (!ctrl) { | ||
| 449 | pixelrate = 0; | ||
| 450 | break; | ||
| 451 | } | ||
| 452 | |||
| 453 | /* All source must report the same pixel rate. */ | ||
| 454 | source_rate = v4l2_ctrl_g_ctrl_int64(ctrl); | ||
| 455 | if (!pixelrate) { | ||
| 456 | pixelrate = source_rate; | ||
| 457 | } else if (pixelrate != source_rate) { | ||
| 458 | dev_err(&priv->client->dev, | ||
| 459 | "Unable to calculate pixel rate\n"); | ||
| 460 | return -EINVAL; | ||
| 461 | } | ||
| 462 | } | ||
| 463 | |||
| 464 | if (!pixelrate) { | ||
| 465 | dev_err(&priv->client->dev, | ||
| 466 | "No pixel rate control available in sources\n"); | ||
| 467 | return -EINVAL; | ||
| 468 | } | ||
| 469 | |||
| 470 | /* | ||
| 471 | * The CSI-2 transmitter pixel rate is the single source rate multiplied | ||
| 472 | * by the number of available sources. | ||
| 473 | */ | ||
| 474 | return v4l2_ctrl_s_ctrl_int64(priv->pixelrate, | ||
| 475 | pixelrate * priv->nsources); | ||
| 476 | } | ||
| 477 | |||
| 478 | static int max9286_notify_bound(struct v4l2_async_notifier *notifier, | ||
| 479 | struct v4l2_subdev *subdev, | ||
| 480 | struct v4l2_async_subdev *asd) | ||
| 481 | { | ||
| 482 | struct max9286_priv *priv = sd_to_max9286(notifier->sd); | ||
| 483 | struct max9286_source *source = asd_to_max9286_source(asd); | ||
| 484 | unsigned int index = to_index(priv, source); | ||
| 485 | unsigned int src_pad; | ||
| 486 | int ret; | ||
| 487 | |||
| 488 | ret = media_entity_get_fwnode_pad(&subdev->entity, | ||
| 489 | source->fwnode, | ||
| 490 | MEDIA_PAD_FL_SOURCE); | ||
| 491 | if (ret < 0) { | ||
| 492 | dev_err(&priv->client->dev, | ||
| 493 | "Failed to find pad for %s\n", subdev->name); | ||
| 494 | return ret; | ||
| 495 | } | ||
| 496 | |||
| 497 | priv->bound_sources |= BIT(index); | ||
| 498 | source->sd = subdev; | ||
| 499 | src_pad = ret; | ||
| 500 | |||
| 501 | ret = media_create_pad_link(&source->sd->entity, src_pad, | ||
| 502 | &priv->sd.entity, index, | ||
| 503 | MEDIA_LNK_FL_ENABLED | | ||
| 504 | MEDIA_LNK_FL_IMMUTABLE); | ||
| 505 | if (ret) { | ||
| 506 | dev_err(&priv->client->dev, | ||
| 507 | "Unable to link %s:%u -> %s:%u\n", | ||
| 508 | source->sd->name, src_pad, priv->sd.name, index); | ||
| 509 | return ret; | ||
| 510 | } | ||
| 511 | |||
| 512 | dev_dbg(&priv->client->dev, "Bound %s pad: %u on index %u\n", | ||
| 513 | subdev->name, src_pad, index); | ||
| 514 | |||
| 515 | /* | ||
| 516 | * We can only register v4l2_async_notifiers, which do not provide a | ||
| 517 | * means to register a complete callback. bound_sources allows us to | ||
| 518 | * identify when all remote serializers have completed their probe. | ||
| 519 | */ | ||
| 520 | if (priv->bound_sources != priv->source_mask) | ||
| 521 | return 0; | ||
| 522 | |||
| 523 | /* | ||
| 524 | * All enabled sources have probed and enabled their reverse control | ||
| 525 | * channels: | ||
| 526 | * | ||
| 527 | * - Verify all configuration links are properly detected | ||
| 528 | * - Disable auto-ack as communication on the control channel are now | ||
| 529 | * stable. | ||
| 530 | */ | ||
| 531 | max9286_check_config_link(priv, priv->source_mask); | ||
| 532 | |||
| 533 | /* | ||
| 534 | * Re-configure I2C with local acknowledge disabled after cameras have | ||
| 535 | * probed. | ||
| 536 | */ | ||
| 537 | max9286_configure_i2c(priv, false); | ||
| 538 | |||
| 539 | return max9286_set_pixelrate(priv); | ||
| 540 | } | ||
| 541 | |||
| 542 | static void max9286_notify_unbind(struct v4l2_async_notifier *notifier, | ||
| 543 | struct v4l2_subdev *subdev, | ||
| 544 | struct v4l2_async_subdev *asd) | ||
| 545 | { | ||
| 546 | struct max9286_priv *priv = sd_to_max9286(notifier->sd); | ||
| 547 | struct max9286_source *source = asd_to_max9286_source(asd); | ||
| 548 | unsigned int index = to_index(priv, source); | ||
| 549 | |||
| 550 | source->sd = NULL; | ||
| 551 | priv->bound_sources &= ~BIT(index); | ||
| 552 | } | ||
| 553 | |||
| 554 | static const struct v4l2_async_notifier_operations max9286_notify_ops = { | ||
| 555 | .bound = max9286_notify_bound, | ||
| 556 | .unbind = max9286_notify_unbind, | ||
| 557 | }; | ||
| 558 | |||
| 559 | static int max9286_v4l2_notifier_register(struct max9286_priv *priv) | ||
| 560 | { | ||
| 561 | struct device *dev = &priv->client->dev; | ||
| 562 | struct max9286_source *source = NULL; | ||
| 563 | int ret; | ||
| 564 | |||
| 565 | if (!priv->nsources) | ||
| 566 | return 0; | ||
| 567 | |||
| 568 | v4l2_async_notifier_init(&priv->notifier); | ||
| 569 | |||
| 570 | for_each_source(priv, source) { | ||
| 571 | unsigned int i = to_index(priv, source); | ||
| 572 | |||
| 573 | source->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; | ||
| 574 | source->asd.match.fwnode = source->fwnode; | ||
| 575 | |||
| 576 | ret = v4l2_async_notifier_add_subdev(&priv->notifier, | ||
| 577 | &source->asd); | ||
| 578 | if (ret) { | ||
| 579 | dev_err(dev, "Failed to add subdev for source %d", i); | ||
| 580 | v4l2_async_notifier_cleanup(&priv->notifier); | ||
| 581 | return ret; | ||
| 582 | } | ||
| 583 | |||
| 584 | /* | ||
| 585 | * Balance the reference counting handled through | ||
| 586 | * v4l2_async_notifier_cleanup() | ||
| 587 | */ | ||
| 588 | fwnode_handle_get(source->fwnode); | ||
| 589 | } | ||
| 590 | |||
| 591 | priv->notifier.ops = &max9286_notify_ops; | ||
| 592 | |||
| 593 | ret = v4l2_async_subdev_notifier_register(&priv->sd, &priv->notifier); | ||
| 594 | if (ret) { | ||
| 595 | dev_err(dev, "Failed to register subdev_notifier"); | ||
| 596 | v4l2_async_notifier_cleanup(&priv->notifier); | ||
| 597 | return ret; | ||
| 598 | } | ||
| 599 | |||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 603 | static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv) | ||
| 604 | { | ||
| 605 | if (!priv->nsources) | ||
| 606 | return; | ||
| 607 | |||
| 608 | v4l2_async_notifier_unregister(&priv->notifier); | ||
| 609 | v4l2_async_notifier_cleanup(&priv->notifier); | ||
| 610 | } | ||
| 611 | |||
| 612 | static int max9286_s_stream(struct v4l2_subdev *sd, int enable) | ||
| 613 | { | ||
| 614 | struct max9286_priv *priv = sd_to_max9286(sd); | ||
| 615 | struct max9286_source *source; | ||
| 616 | unsigned int i; | ||
| 617 | bool sync = false; | ||
| 618 | int ret; | ||
| 619 | |||
| 620 | if (enable) { | ||
| 621 | /* | ||
| 622 | * The frame sync between cameras is transmitted across the | ||
| 623 | * reverse channel as GPIO. We must open all channels while | ||
| 624 | * streaming to allow this synchronisation signal to be shared. | ||
| 625 | */ | ||
| 626 | max9286_i2c_mux_open(priv); | ||
| 627 | |||
| 628 | /* Start all cameras. */ | ||
| 629 | for_each_source(priv, source) { | ||
| 630 | ret = v4l2_subdev_call(source->sd, video, s_stream, 1); | ||
| 631 | if (ret) | ||
| 632 | return ret; | ||
| 633 | } | ||
| 634 | |||
| 635 | ret = max9286_check_video_links(priv); | ||
| 636 | if (ret) | ||
| 637 | return ret; | ||
| 638 | |||
| 639 | /* | ||
| 640 | * Wait until frame synchronization is locked. | ||
| 641 | * | ||
| 642 | * Manual says frame sync locking should take ~6 VTS. | ||
| 643 | * From practical experience at least 8 are required. Give | ||
| 644 | * 12 complete frames time (~400ms at 30 fps) to achieve frame | ||
| 645 | * locking before returning error. | ||
| 646 | */ | ||
| 647 | for (i = 0; i < 40; i++) { | ||
| 648 | if (max9286_read(priv, 0x31) & MAX9286_FSYNC_LOCKED) { | ||
| 649 | sync = true; | ||
| 650 | break; | ||
| 651 | } | ||
| 652 | usleep_range(9000, 11000); | ||
| 653 | } | ||
| 654 | |||
| 655 | if (!sync) { | ||
| 656 | dev_err(&priv->client->dev, | ||
| 657 | "Failed to get frame synchronization\n"); | ||
| 658 | return -EXDEV; /* Invalid cross-device link */ | ||
| 659 | } | ||
| 660 | |||
| 661 | /* | ||
| 662 | * Enable CSI output, VC set according to link number. | ||
| 663 | * Bit 7 must be set (chip manual says it's 0 and reserved). | ||
| 664 | */ | ||
| 665 | max9286_write(priv, 0x15, 0x80 | MAX9286_VCTYPE | | ||
| 666 | MAX9286_CSIOUTEN | MAX9286_0X15_RESV); | ||
| 667 | } else { | ||
| 668 | max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV); | ||
| 669 | |||
| 670 | /* Stop all cameras. */ | ||
| 671 | for_each_source(priv, source) | ||
| 672 | v4l2_subdev_call(source->sd, video, s_stream, 0); | ||
| 673 | |||
| 674 | max9286_i2c_mux_close(priv); | ||
| 675 | } | ||
| 676 | |||
| 677 | return 0; | ||
| 678 | } | ||
| 679 | |||
| 680 | static int max9286_enum_mbus_code(struct v4l2_subdev *sd, | ||
| 681 | struct v4l2_subdev_pad_config *cfg, | ||
| 682 | struct v4l2_subdev_mbus_code_enum *code) | ||
| 683 | { | ||
| 684 | if (code->pad || code->index > 0) | ||
| 685 | return -EINVAL; | ||
| 686 | |||
| 687 | code->code = MEDIA_BUS_FMT_UYVY8_1X16; | ||
| 688 | |||
| 689 | return 0; | ||
| 690 | } | ||
| 691 | |||
| 692 | static struct v4l2_mbus_framefmt * | ||
| 693 | max9286_get_pad_format(struct max9286_priv *priv, | ||
| 694 | struct v4l2_subdev_pad_config *cfg, | ||
| 695 | unsigned int pad, u32 which) | ||
| 696 | { | ||
| 697 | switch (which) { | ||
| 698 | case V4L2_SUBDEV_FORMAT_TRY: | ||
| 699 | return v4l2_subdev_get_try_format(&priv->sd, cfg, pad); | ||
| 700 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
| 701 | return &priv->fmt[pad]; | ||
| 702 | default: | ||
| 703 | return NULL; | ||
| 704 | } | ||
| 705 | } | ||
| 706 | |||
| 707 | static int max9286_set_fmt(struct v4l2_subdev *sd, | ||
| 708 | struct v4l2_subdev_pad_config *cfg, | ||
| 709 | struct v4l2_subdev_format *format) | ||
| 710 | { | ||
| 711 | struct max9286_priv *priv = sd_to_max9286(sd); | ||
| 712 | struct v4l2_mbus_framefmt *cfg_fmt; | ||
| 713 | |||
| 714 | if (format->pad == MAX9286_SRC_PAD) | ||
| 715 | return -EINVAL; | ||
| 716 | |||
| 717 | /* Refuse non YUV422 formats as we hardcode DT to 8 bit YUV422 */ | ||
| 718 | switch (format->format.code) { | ||
| 719 | case MEDIA_BUS_FMT_UYVY8_1X16: | ||
| 720 | case MEDIA_BUS_FMT_VYUY8_1X16: | ||
| 721 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
| 722 | case MEDIA_BUS_FMT_YVYU8_1X16: | ||
| 723 | break; | ||
| 724 | default: | ||
| 725 | format->format.code = MEDIA_BUS_FMT_UYVY8_1X16; | ||
| 726 | break; | ||
| 727 | } | ||
| 728 | |||
| 729 | cfg_fmt = max9286_get_pad_format(priv, cfg, format->pad, format->which); | ||
| 730 | if (!cfg_fmt) | ||
| 731 | return -EINVAL; | ||
| 732 | |||
| 733 | mutex_lock(&priv->mutex); | ||
| 734 | *cfg_fmt = format->format; | ||
| 735 | mutex_unlock(&priv->mutex); | ||
| 736 | |||
| 737 | return 0; | ||
| 738 | } | ||
| 739 | |||
| 740 | static int max9286_get_fmt(struct v4l2_subdev *sd, | ||
| 741 | struct v4l2_subdev_pad_config *cfg, | ||
| 742 | struct v4l2_subdev_format *format) | ||
| 743 | { | ||
| 744 | struct max9286_priv *priv = sd_to_max9286(sd); | ||
| 745 | struct v4l2_mbus_framefmt *cfg_fmt; | ||
| 746 | unsigned int pad = format->pad; | ||
| 747 | |||
| 748 | /* | ||
| 749 | * Multiplexed Stream Support: Support link validation by returning the | ||
| 750 | * format of the first bound link. All links must have the same format, | ||
| 751 | * as we do not support mixing and matching of cameras connected to the | ||
| 752 | * max9286. | ||
| 753 | */ | ||
| 754 | if (pad == MAX9286_SRC_PAD) | ||
| 755 | pad = __ffs(priv->bound_sources); | ||
| 756 | |||
| 757 | cfg_fmt = max9286_get_pad_format(priv, cfg, pad, format->which); | ||
| 758 | if (!cfg_fmt) | ||
| 759 | return -EINVAL; | ||
| 760 | |||
| 761 | mutex_lock(&priv->mutex); | ||
| 762 | format->format = *cfg_fmt; | ||
| 763 | mutex_unlock(&priv->mutex); | ||
| 764 | |||
| 765 | return 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | static const struct v4l2_subdev_video_ops max9286_video_ops = { | ||
| 769 | .s_stream = max9286_s_stream, | ||
| 770 | }; | ||
| 771 | |||
| 772 | static const struct v4l2_subdev_pad_ops max9286_pad_ops = { | ||
| 773 | .enum_mbus_code = max9286_enum_mbus_code, | ||
| 774 | .get_fmt = max9286_get_fmt, | ||
| 775 | .set_fmt = max9286_set_fmt, | ||
| 776 | }; | ||
| 777 | |||
| 778 | static const struct v4l2_subdev_ops max9286_subdev_ops = { | ||
| 779 | .video = &max9286_video_ops, | ||
| 780 | .pad = &max9286_pad_ops, | ||
| 781 | }; | ||
| 782 | |||
| 783 | static void max9286_init_format(struct v4l2_mbus_framefmt *fmt) | ||
| 784 | { | ||
| 785 | fmt->width = 1280; | ||
| 786 | fmt->height = 800; | ||
| 787 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; | ||
| 788 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | ||
| 789 | fmt->field = V4L2_FIELD_NONE; | ||
| 790 | fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | ||
| 791 | fmt->quantization = V4L2_QUANTIZATION_DEFAULT; | ||
| 792 | fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; | ||
| 793 | } | ||
| 794 | |||
| 795 | static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | ||
| 796 | { | ||
| 797 | struct v4l2_mbus_framefmt *format; | ||
| 798 | unsigned int i; | ||
| 799 | |||
| 800 | for (i = 0; i < MAX9286_N_SINKS; i++) { | ||
| 801 | format = v4l2_subdev_get_try_format(subdev, fh->pad, i); | ||
| 802 | max9286_init_format(format); | ||
| 803 | } | ||
| 804 | |||
| 805 | return 0; | ||
| 806 | } | ||
| 807 | |||
| 808 | static const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = { | ||
| 809 | .open = max9286_open, | ||
| 810 | }; | ||
| 811 | |||
| 812 | static int max9286_s_ctrl(struct v4l2_ctrl *ctrl) | ||
| 813 | { | ||
| 814 | switch (ctrl->id) { | ||
| 815 | case V4L2_CID_PIXEL_RATE: | ||
| 816 | return 0; | ||
| 817 | default: | ||
| 818 | return -EINVAL; | ||
| 819 | } | ||
| 820 | } | ||
| 821 | |||
| 822 | static const struct v4l2_ctrl_ops max9286_ctrl_ops = { | ||
| 823 | .s_ctrl = max9286_s_ctrl, | ||
| 824 | }; | ||
| 825 | |||
| 826 | static int max9286_v4l2_register(struct max9286_priv *priv) | ||
| 827 | { | ||
| 828 | struct device *dev = &priv->client->dev; | ||
| 829 | struct fwnode_handle *ep; | ||
| 830 | int ret; | ||
| 831 | int i; | ||
| 832 | |||
| 833 | /* Register v4l2 async notifiers for connected Camera subdevices */ | ||
| 834 | ret = max9286_v4l2_notifier_register(priv); | ||
| 835 | if (ret) { | ||
| 836 | dev_err(dev, "Unable to register V4L2 async notifiers\n"); | ||
| 837 | return ret; | ||
| 838 | } | ||
| 839 | |||
| 840 | /* Configure V4L2 for the MAX9286 itself */ | ||
| 841 | |||
| 842 | for (i = 0; i < MAX9286_N_SINKS; i++) | ||
| 843 | max9286_init_format(&priv->fmt[i]); | ||
| 844 | |||
| 845 | v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops); | ||
| 846 | priv->sd.internal_ops = &max9286_subdev_internal_ops; | ||
| 847 | priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 848 | |||
| 849 | v4l2_ctrl_handler_init(&priv->ctrls, 1); | ||
| 850 | priv->pixelrate = v4l2_ctrl_new_std(&priv->ctrls, | ||
| 851 | &max9286_ctrl_ops, | ||
| 852 | V4L2_CID_PIXEL_RATE, | ||
| 853 | 1, INT_MAX, 1, 50000000); | ||
| 854 | |||
| 855 | priv->sd.ctrl_handler = &priv->ctrls; | ||
| 856 | ret = priv->ctrls.error; | ||
| 857 | if (ret) | ||
| 858 | goto err_async; | ||
| 859 | |||
| 860 | priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; | ||
| 861 | |||
| 862 | priv->pads[MAX9286_SRC_PAD].flags = MEDIA_PAD_FL_SOURCE; | ||
| 863 | for (i = 0; i < MAX9286_SRC_PAD; i++) | ||
| 864 | priv->pads[i].flags = MEDIA_PAD_FL_SINK; | ||
| 865 | ret = media_entity_pads_init(&priv->sd.entity, MAX9286_N_PADS, | ||
| 866 | priv->pads); | ||
| 867 | if (ret) | ||
| 868 | goto err_async; | ||
| 869 | |||
| 870 | ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), MAX9286_SRC_PAD, | ||
| 871 | 0, 0); | ||
| 872 | if (!ep) { | ||
| 873 | dev_err(dev, "Unable to retrieve endpoint on \"port@4\"\n"); | ||
| 874 | ret = -ENOENT; | ||
| 875 | goto err_async; | ||
| 876 | } | ||
| 877 | priv->sd.fwnode = ep; | ||
| 878 | |||
| 879 | ret = v4l2_async_register_subdev(&priv->sd); | ||
| 880 | if (ret < 0) { | ||
| 881 | dev_err(dev, "Unable to register subdevice\n"); | ||
| 882 | goto err_put_node; | ||
| 883 | } | ||
| 884 | |||
| 885 | return 0; | ||
| 886 | |||
| 887 | err_put_node: | ||
| 888 | fwnode_handle_put(ep); | ||
| 889 | err_async: | ||
| 890 | max9286_v4l2_notifier_unregister(priv); | ||
| 891 | |||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | static void max9286_v4l2_unregister(struct max9286_priv *priv) | ||
| 896 | { | ||
| 897 | fwnode_handle_put(priv->sd.fwnode); | ||
| 898 | v4l2_async_unregister_subdev(&priv->sd); | ||
| 899 | max9286_v4l2_notifier_unregister(priv); | ||
| 900 | } | ||
| 901 | |||
| 902 | /* ----------------------------------------------------------------------------- | ||
| 903 | * Probe/Remove | ||
| 904 | */ | ||
| 905 | |||
| 906 | static int max9286_setup(struct max9286_priv *priv) | ||
| 907 | { | ||
| 908 | /* | ||
| 909 | * Link ordering values for all enabled links combinations. Orders must | ||
| 910 | * be assigned sequentially from 0 to the number of enabled links | ||
| 911 | * without leaving any hole for disabled links. We thus assign orders to | ||
| 912 | * enabled links first, and use the remaining order values for disabled | ||
| 913 | * links are all links must have a different order value; | ||
| 914 | */ | ||
| 915 | static const u8 link_order[] = { | ||
| 916 | (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxxx */ | ||
| 917 | (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxx0 */ | ||
| 918 | (3 << 6) | (2 << 4) | (0 << 2) | (1 << 0), /* xx0x */ | ||
| 919 | (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xx10 */ | ||
| 920 | (3 << 6) | (0 << 4) | (2 << 2) | (1 << 0), /* x0xx */ | ||
| 921 | (3 << 6) | (1 << 4) | (2 << 2) | (0 << 0), /* x1x0 */ | ||
| 922 | (3 << 6) | (1 << 4) | (0 << 2) | (2 << 0), /* x10x */ | ||
| 923 | (3 << 6) | (1 << 4) | (1 << 2) | (0 << 0), /* x210 */ | ||
| 924 | (0 << 6) | (3 << 4) | (2 << 2) | (1 << 0), /* 0xxx */ | ||
| 925 | (1 << 6) | (3 << 4) | (2 << 2) | (0 << 0), /* 1xx0 */ | ||
| 926 | (1 << 6) | (3 << 4) | (0 << 2) | (2 << 0), /* 1x0x */ | ||
| 927 | (2 << 6) | (3 << 4) | (1 << 2) | (0 << 0), /* 2x10 */ | ||
| 928 | (1 << 6) | (0 << 4) | (3 << 2) | (2 << 0), /* 10xx */ | ||
| 929 | (2 << 6) | (1 << 4) | (3 << 2) | (0 << 0), /* 21x0 */ | ||
| 930 | (2 << 6) | (1 << 4) | (0 << 2) | (3 << 0), /* 210x */ | ||
| 931 | (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* 3210 */ | ||
| 932 | }; | ||
| 933 | |||
| 934 | /* | ||
| 935 | * Set the I2C bus speed. | ||
| 936 | * | ||
| 937 | * Enable I2C Local Acknowledge during the probe sequences of the camera | ||
| 938 | * only. This should be disabled after the mux is initialised. | ||
| 939 | */ | ||
| 940 | max9286_configure_i2c(priv, true); | ||
| 941 | |||
| 942 | /* | ||
| 943 | * Reverse channel setup. | ||
| 944 | * | ||
| 945 | * - Enable custom reverse channel configuration (through register 0x3f) | ||
| 946 | * and set the first pulse length to 35 clock cycles. | ||
| 947 | * - Increase the reverse channel amplitude to 170mV to accommodate the | ||
| 948 | * high threshold enabled by the serializer driver. | ||
| 949 | */ | ||
| 950 | max9286_write(priv, 0x3f, MAX9286_EN_REV_CFG | MAX9286_REV_FLEN(35)); | ||
| 951 | max9286_write(priv, 0x3b, MAX9286_REV_TRF(1) | MAX9286_REV_AMP(70) | | ||
| 952 | MAX9286_REV_AMP_X); | ||
| 953 | usleep_range(2000, 2500); | ||
| 954 | |||
| 955 | /* | ||
| 956 | * Enable GMSL links, mask unused ones and autodetect link | ||
| 957 | * used as CSI clock source. | ||
| 958 | */ | ||
| 959 | max9286_write(priv, 0x00, MAX9286_MSTLINKSEL_AUTO | priv->route_mask); | ||
| 960 | max9286_write(priv, 0x0b, link_order[priv->route_mask]); | ||
| 961 | max9286_write(priv, 0x69, (0xf & ~priv->route_mask)); | ||
| 962 | |||
| 963 | /* | ||
| 964 | * Video format setup: | ||
| 965 | * Disable CSI output, VC is set according to Link number. | ||
| 966 | */ | ||
| 967 | max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_0X15_RESV); | ||
| 968 | |||
| 969 | /* Enable CSI-2 Lane D0-D3 only, DBL mode, YUV422 8-bit. */ | ||
| 970 | max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL | | ||
| 971 | MAX9286_CSILANECNT(priv->csi2_data_lanes) | | ||
| 972 | MAX9286_DATATYPE_YUV422_8BIT); | ||
| 973 | |||
| 974 | /* Automatic: FRAMESYNC taken from the slowest Link. */ | ||
| 975 | max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ | | ||
| 976 | MAX9286_FSYNCMETH_AUTO); | ||
| 977 | |||
| 978 | /* Enable HS/VS encoding, use D14/15 for HS/VS, invert VS. */ | ||
| 979 | max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_INVVS | | ||
| 980 | MAX9286_HVSRC_D14); | ||
| 981 | |||
| 982 | /* | ||
| 983 | * The overlap window seems to provide additional validation by tracking | ||
| 984 | * the delay between vsync and frame sync, generating an error if the | ||
| 985 | * delay is bigger than the programmed window, though it's not yet clear | ||
| 986 | * what value should be set. | ||
| 987 | * | ||
| 988 | * As it's an optional value and can be disabled, we do so by setting | ||
| 989 | * a 0 overlap value. | ||
| 990 | */ | ||
| 991 | max9286_write(priv, 0x63, 0); | ||
| 992 | max9286_write(priv, 0x64, 0); | ||
| 993 | |||
| 994 | /* | ||
| 995 | * Wait for 2ms to allow the link to resynchronize after the | ||
| 996 | * configuration change. | ||
| 997 | */ | ||
| 998 | usleep_range(2000, 5000); | ||
| 999 | |||
| 1000 | return 0; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | static void max9286_gpio_set(struct gpio_chip *chip, | ||
| 1004 | unsigned int offset, int value) | ||
| 1005 | { | ||
| 1006 | struct max9286_priv *priv = gpiochip_get_data(chip); | ||
| 1007 | |||
| 1008 | if (value) | ||
| 1009 | priv->gpio_state |= BIT(offset); | ||
| 1010 | else | ||
| 1011 | priv->gpio_state &= ~BIT(offset); | ||
| 1012 | |||
| 1013 | max9286_write(priv, 0x0f, MAX9286_0X0F_RESERVED | priv->gpio_state); | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | static int max9286_gpio_get(struct gpio_chip *chip, unsigned int offset) | ||
| 1017 | { | ||
| 1018 | struct max9286_priv *priv = gpiochip_get_data(chip); | ||
| 1019 | |||
| 1020 | return priv->gpio_state & BIT(offset); | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | static int max9286_register_gpio(struct max9286_priv *priv) | ||
| 1024 | { | ||
| 1025 | struct device *dev = &priv->client->dev; | ||
| 1026 | struct gpio_chip *gpio = &priv->gpio; | ||
| 1027 | int ret; | ||
| 1028 | |||
| 1029 | /* Configure the GPIO */ | ||
| 1030 | gpio->label = dev_name(dev); | ||
| 1031 | gpio->parent = dev; | ||
| 1032 | gpio->owner = THIS_MODULE; | ||
| 1033 | gpio->of_node = dev->of_node; | ||
| 1034 | gpio->ngpio = 2; | ||
| 1035 | gpio->base = -1; | ||
| 1036 | gpio->set = max9286_gpio_set; | ||
| 1037 | gpio->get = max9286_gpio_get; | ||
| 1038 | gpio->can_sleep = true; | ||
| 1039 | |||
| 1040 | /* GPIO values default to high */ | ||
| 1041 | priv->gpio_state = BIT(0) | BIT(1); | ||
| 1042 | |||
| 1043 | ret = devm_gpiochip_add_data(dev, gpio, priv); | ||
| 1044 | if (ret) | ||
| 1045 | dev_err(dev, "Unable to create gpio_chip\n"); | ||
| 1046 | |||
| 1047 | return ret; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static int max9286_init(struct device *dev) | ||
| 1051 | { | ||
| 1052 | struct max9286_priv *priv; | ||
| 1053 | struct i2c_client *client; | ||
| 1054 | int ret; | ||
| 1055 | |||
| 1056 | client = to_i2c_client(dev); | ||
| 1057 | priv = i2c_get_clientdata(client); | ||
| 1058 | |||
| 1059 | /* Enable the bus power. */ | ||
| 1060 | ret = regulator_enable(priv->regulator); | ||
| 1061 | if (ret < 0) { | ||
| 1062 | dev_err(&client->dev, "Unable to turn PoC on\n"); | ||
| 1063 | return ret; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | ret = max9286_setup(priv); | ||
| 1067 | if (ret) { | ||
| 1068 | dev_err(dev, "Unable to setup max9286\n"); | ||
| 1069 | goto err_regulator; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | /* | ||
| 1073 | * Register all V4L2 interactions for the MAX9286 and notifiers for | ||
| 1074 | * any subdevices connected. | ||
| 1075 | */ | ||
| 1076 | ret = max9286_v4l2_register(priv); | ||
| 1077 | if (ret) { | ||
| 1078 | dev_err(dev, "Failed to register with V4L2\n"); | ||
| 1079 | goto err_regulator; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | ret = max9286_i2c_mux_init(priv); | ||
| 1083 | if (ret) { | ||
| 1084 | dev_err(dev, "Unable to initialize I2C multiplexer\n"); | ||
| 1085 | goto err_v4l2_register; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | /* Leave the mux channels disabled until they are selected. */ | ||
| 1089 | max9286_i2c_mux_close(priv); | ||
| 1090 | |||
| 1091 | return 0; | ||
| 1092 | |||
| 1093 | err_v4l2_register: | ||
| 1094 | max9286_v4l2_unregister(priv); | ||
| 1095 | err_regulator: | ||
| 1096 | regulator_disable(priv->regulator); | ||
| 1097 | |||
| 1098 | return ret; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | static void max9286_cleanup_dt(struct max9286_priv *priv) | ||
| 1102 | { | ||
| 1103 | struct max9286_source *source; | ||
| 1104 | |||
| 1105 | for_each_source(priv, source) { | ||
| 1106 | fwnode_handle_put(source->fwnode); | ||
| 1107 | source->fwnode = NULL; | ||
| 1108 | } | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | static int max9286_parse_dt(struct max9286_priv *priv) | ||
| 1112 | { | ||
| 1113 | struct device *dev = &priv->client->dev; | ||
| 1114 | struct device_node *i2c_mux; | ||
| 1115 | struct device_node *node = NULL; | ||
| 1116 | unsigned int i2c_mux_mask = 0; | ||
| 1117 | |||
| 1118 | /* Balance the of_node_put() performed by of_find_node_by_name(). */ | ||
| 1119 | of_node_get(dev->of_node); | ||
| 1120 | i2c_mux = of_find_node_by_name(dev->of_node, "i2c-mux"); | ||
| 1121 | if (!i2c_mux) { | ||
| 1122 | dev_err(dev, "Failed to find i2c-mux node\n"); | ||
| 1123 | return -EINVAL; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | /* Identify which i2c-mux channels are enabled */ | ||
| 1127 | for_each_child_of_node(i2c_mux, node) { | ||
| 1128 | u32 id = 0; | ||
| 1129 | |||
| 1130 | of_property_read_u32(node, "reg", &id); | ||
| 1131 | if (id >= MAX9286_NUM_GMSL) | ||
| 1132 | continue; | ||
| 1133 | |||
| 1134 | if (!of_device_is_available(node)) { | ||
| 1135 | dev_dbg(dev, "Skipping disabled I2C bus port %u\n", id); | ||
| 1136 | continue; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | i2c_mux_mask |= BIT(id); | ||
| 1140 | } | ||
| 1141 | of_node_put(node); | ||
| 1142 | of_node_put(i2c_mux); | ||
| 1143 | |||
| 1144 | /* Parse the endpoints */ | ||
| 1145 | for_each_endpoint_of_node(dev->of_node, node) { | ||
| 1146 | struct max9286_source *source; | ||
| 1147 | struct of_endpoint ep; | ||
| 1148 | |||
| 1149 | of_graph_parse_endpoint(node, &ep); | ||
| 1150 | dev_dbg(dev, "Endpoint %pOF on port %d", | ||
| 1151 | ep.local_node, ep.port); | ||
| 1152 | |||
| 1153 | if (ep.port > MAX9286_NUM_GMSL) { | ||
| 1154 | dev_err(dev, "Invalid endpoint %s on port %d", | ||
| 1155 | of_node_full_name(ep.local_node), ep.port); | ||
| 1156 | continue; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | /* For the source endpoint just parse the bus configuration. */ | ||
| 1160 | if (ep.port == MAX9286_SRC_PAD) { | ||
| 1161 | struct v4l2_fwnode_endpoint vep = { | ||
| 1162 | .bus_type = V4L2_MBUS_CSI2_DPHY | ||
| 1163 | }; | ||
| 1164 | int ret; | ||
| 1165 | |||
| 1166 | ret = v4l2_fwnode_endpoint_parse( | ||
| 1167 | of_fwnode_handle(node), &vep); | ||
| 1168 | if (ret) { | ||
| 1169 | of_node_put(node); | ||
| 1170 | return ret; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | priv->csi2_data_lanes = | ||
| 1174 | vep.bus.mipi_csi2.num_data_lanes; | ||
| 1175 | |||
| 1176 | continue; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | /* Skip if the corresponding GMSL link is unavailable. */ | ||
| 1180 | if (!(i2c_mux_mask & BIT(ep.port))) | ||
| 1181 | continue; | ||
| 1182 | |||
| 1183 | if (priv->sources[ep.port].fwnode) { | ||
| 1184 | dev_err(dev, | ||
| 1185 | "Multiple port endpoints are not supported: %d", | ||
| 1186 | ep.port); | ||
| 1187 | |||
| 1188 | continue; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | source = &priv->sources[ep.port]; | ||
| 1192 | source->fwnode = fwnode_graph_get_remote_endpoint( | ||
| 1193 | of_fwnode_handle(node)); | ||
| 1194 | if (!source->fwnode) { | ||
| 1195 | dev_err(dev, | ||
| 1196 | "Endpoint %pOF has no remote endpoint connection\n", | ||
| 1197 | ep.local_node); | ||
| 1198 | |||
| 1199 | continue; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | priv->source_mask |= BIT(ep.port); | ||
| 1203 | priv->nsources++; | ||
| 1204 | } | ||
| 1205 | of_node_put(node); | ||
| 1206 | |||
| 1207 | priv->route_mask = priv->source_mask; | ||
| 1208 | |||
| 1209 | return 0; | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | static int max9286_probe(struct i2c_client *client) | ||
| 1213 | { | ||
| 1214 | struct max9286_priv *priv; | ||
| 1215 | int ret; | ||
| 1216 | |||
| 1217 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); | ||
| 1218 | if (!priv) | ||
| 1219 | return -ENOMEM; | ||
| 1220 | |||
| 1221 | mutex_init(&priv->mutex); | ||
| 1222 | |||
| 1223 | priv->client = client; | ||
| 1224 | i2c_set_clientdata(client, priv); | ||
| 1225 | |||
| 1226 | priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable", | ||
| 1227 | GPIOD_OUT_HIGH); | ||
| 1228 | if (IS_ERR(priv->gpiod_pwdn)) | ||
| 1229 | return PTR_ERR(priv->gpiod_pwdn); | ||
| 1230 | |||
| 1231 | gpiod_set_consumer_name(priv->gpiod_pwdn, "max9286-pwdn"); | ||
| 1232 | gpiod_set_value_cansleep(priv->gpiod_pwdn, 1); | ||
| 1233 | |||
| 1234 | /* Wait at least 4ms before the I2C lines latch to the address */ | ||
| 1235 | if (priv->gpiod_pwdn) | ||
| 1236 | usleep_range(4000, 5000); | ||
| 1237 | |||
| 1238 | /* | ||
| 1239 | * The MAX9286 starts by default with all ports enabled, we disable all | ||
| 1240 | * ports early to ensure that all channels are disabled if we error out | ||
| 1241 | * and keep the bus consistent. | ||
| 1242 | */ | ||
| 1243 | max9286_i2c_mux_close(priv); | ||
| 1244 | |||
| 1245 | /* | ||
| 1246 | * The MAX9286 initialises with auto-acknowledge enabled by default. | ||
| 1247 | * This can be invasive to other transactions on the same bus, so | ||
| 1248 | * disable it early. It will be enabled only as and when needed. | ||
| 1249 | */ | ||
| 1250 | max9286_configure_i2c(priv, false); | ||
| 1251 | |||
| 1252 | ret = max9286_register_gpio(priv); | ||
| 1253 | if (ret) | ||
| 1254 | goto err_powerdown; | ||
| 1255 | |||
| 1256 | priv->regulator = devm_regulator_get(&client->dev, "poc"); | ||
| 1257 | if (IS_ERR(priv->regulator)) { | ||
| 1258 | if (PTR_ERR(priv->regulator) != -EPROBE_DEFER) | ||
| 1259 | dev_err(&client->dev, | ||
| 1260 | "Unable to get PoC regulator (%ld)\n", | ||
| 1261 | PTR_ERR(priv->regulator)); | ||
| 1262 | ret = PTR_ERR(priv->regulator); | ||
| 1263 | goto err_powerdown; | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | ret = max9286_parse_dt(priv); | ||
| 1267 | if (ret) | ||
| 1268 | goto err_powerdown; | ||
| 1269 | |||
| 1270 | ret = max9286_init(&client->dev); | ||
| 1271 | if (ret < 0) | ||
| 1272 | goto err_cleanup_dt; | ||
| 1273 | |||
| 1274 | return 0; | ||
| 1275 | |||
| 1276 | err_cleanup_dt: | ||
| 1277 | max9286_cleanup_dt(priv); | ||
| 1278 | err_powerdown: | ||
| 1279 | gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); | ||
| 1280 | |||
| 1281 | return ret; | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | static int max9286_remove(struct i2c_client *client) | ||
| 1285 | { | ||
| 1286 | struct max9286_priv *priv = i2c_get_clientdata(client); | ||
| 1287 | |||
| 1288 | i2c_mux_del_adapters(priv->mux); | ||
| 1289 | |||
| 1290 | max9286_v4l2_unregister(priv); | ||
| 1291 | |||
| 1292 | regulator_disable(priv->regulator); | ||
| 1293 | |||
| 1294 | gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); | ||
| 1295 | |||
| 1296 | max9286_cleanup_dt(priv); | ||
| 1297 | |||
| 1298 | return 0; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | static const struct of_device_id max9286_dt_ids[] = { | ||
| 1302 | { .compatible = "maxim,max9286" }, | ||
| 1303 | {}, | ||
| 1304 | }; | ||
| 1305 | MODULE_DEVICE_TABLE(of, max9286_dt_ids); | ||
| 1306 | |||
| 1307 | static struct i2c_driver max9286_i2c_driver = { | ||
| 1308 | .driver = { | ||
| 1309 | .name = "max9286", | ||
| 1310 | .of_match_table = of_match_ptr(max9286_dt_ids), | ||
| 1311 | }, | ||
| 1312 | .probe_new = max9286_probe, | ||
| 1313 | .remove = max9286_remove, | ||
| 1314 | }; | ||
| 1315 | |||
| 1316 | module_i2c_driver(max9286_i2c_driver); | ||
| 1317 | |||
| 1318 | MODULE_DESCRIPTION("Maxim MAX9286 GMSL Deserializer Driver"); | ||
| 1319 | MODULE_AUTHOR("Jacopo Mondi, Kieran Bingham, Laurent Pinchart, Niklas Söderlund, Vladimir Barinov"); | ||
| 1320 | MODULE_LICENSE("GPL"); | ||
| @@ -7,6 +7,8 @@ · 6 unmodified lines | |||
| 7 | #include <linux/i2c.h> | 7 | #include <linux/i2c.h> |
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/pm_runtime.h> | 9 | #include <linux/pm_runtime.h> |
| 10 | #include <linux/nvmem-provider.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 10 | #include <media/v4l2-ctrls.h> | 12 | #include <media/v4l2-ctrls.h> |
| 11 | #include <media/v4l2-device.h> | 13 | #include <media/v4l2-device.h> |
| 12 | #include <media/v4l2-fwnode.h> | 14 | #include <media/v4l2-fwnode.h> |
| @@ -59,6 +61,21 @@ · 46 unmodified lines | |||
| 59 | #define OV2740_TEST_PATTERN_ENABLE BIT(7) | 61 | #define OV2740_TEST_PATTERN_ENABLE BIT(7) |
| 60 | #define OV2740_TEST_PATTERN_BAR_SHIFT 2 | 62 | #define OV2740_TEST_PATTERN_BAR_SHIFT 2 |
| 61 | 63 | ||
| 64 | /* ISP CTRL00 */ | ||
| 65 | #define OV2740_REG_ISP_CTRL00 0x5000 | ||
| 66 | /* ISP CTRL01 */ | ||
| 67 | #define OV2740_REG_ISP_CTRL01 0x5001 | ||
| 68 | /* Customer Addresses: 0x7010 - 0x710F */ | ||
| 69 | #define CUSTOMER_USE_OTP_SIZE 0x100 | ||
| 70 | /* OTP registers from sensor */ | ||
| 71 | #define OV2740_REG_OTP_CUSTOMER 0x7010 | ||
| 72 | |||
| 73 | struct nvm_data { | ||
| 74 | char *nvm_buffer; | ||
| 75 | struct nvmem_device *nvmem; | ||
| 76 | struct regmap *regmap; | ||
| 77 | }; | ||
| 78 | |||
| 62 | enum { | 79 | enum { |
| 63 | OV2740_LINK_FREQ_360MHZ_INDEX, | 80 | OV2740_LINK_FREQ_360MHZ_INDEX, |
| 64 | }; | 81 | }; |
| @@ -915,6 +932,130 @@ static int ov2740_remove(struct i2c_client *client) · 850 unmodified lines | |||
| 915 | return 0; | 932 | return 0; |
| 916 | } | 933 | } |
| 917 | 934 | ||
| 935 | static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm) | ||
| 936 | { | ||
| 937 | struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client)); | ||
| 938 | u32 isp_ctrl00 = 0; | ||
| 939 | u32 isp_ctrl01 = 0; | ||
| 940 | int ret; | ||
| 941 | |||
| 942 | ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00); | ||
| 943 | if (ret) { | ||
| 944 | dev_err(&client->dev, "failed to read ISP CTRL00\n"); | ||
| 945 | goto exit; | ||
| 946 | } | ||
| 947 | ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01); | ||
| 948 | if (ret) { | ||
| 949 | dev_err(&client->dev, "failed to read ISP CTRL01\n"); | ||
| 950 | goto exit; | ||
| 951 | } | ||
| 952 | |||
| 953 | /* Clear bit 5 of ISP CTRL00 */ | ||
| 954 | ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, | ||
| 955 | isp_ctrl00 & ~BIT(5)); | ||
| 956 | if (ret) { | ||
| 957 | dev_err(&client->dev, "failed to write ISP CTRL00\n"); | ||
| 958 | goto exit; | ||
| 959 | } | ||
| 960 | |||
| 961 | /* Clear bit 7 of ISP CTRL01 */ | ||
| 962 | ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, | ||
| 963 | isp_ctrl01 & ~BIT(7)); | ||
| 964 | if (ret) { | ||
| 965 | dev_err(&client->dev, "failed to write ISP CTRL01\n"); | ||
| 966 | goto exit; | ||
| 967 | } | ||
| 968 | |||
| 969 | ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, | ||
| 970 | OV2740_MODE_STREAMING); | ||
| 971 | if (ret) { | ||
| 972 | dev_err(&client->dev, "failed to start streaming\n"); | ||
| 973 | goto exit; | ||
| 974 | } | ||
| 975 | |||
| 976 | /* | ||
| 977 | * Users are not allowed to access OTP-related registers and memory | ||
| 978 | * during the 20 ms period after streaming starts (0x100 = 0x01). | ||
| 979 | */ | ||
| 980 | msleep(20); | ||
| 981 | |||
| 982 | ret = regmap_bulk_read(nvm->regmap, OV2740_REG_OTP_CUSTOMER, | ||
| 983 | nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE); | ||
| 984 | if (ret) { | ||
| 985 | dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret); | ||
| 986 | goto exit; | ||
| 987 | } | ||
| 988 | |||
| 989 | ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, | ||
| 990 | OV2740_MODE_STANDBY); | ||
| 991 | ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01); | ||
| 992 | ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00); | ||
| 993 | |||
| 994 | exit: | ||
| 995 | return ret; | ||
| 996 | } | ||
| 997 | |||
| 998 | static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, | ||
| 999 | size_t count) | ||
| 1000 | { | ||
| 1001 | struct nvm_data *nvm = priv; | ||
| 1002 | |||
| 1003 | memcpy(val, nvm->nvm_buffer + off, count); | ||
| 1004 | |||
| 1005 | return 0; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | static int ov2740_register_nvmem(struct i2c_client *client) | ||
| 1009 | { | ||
| 1010 | struct nvm_data *nvm; | ||
| 1011 | struct regmap_config regmap_config = { }; | ||
| 1012 | struct nvmem_config nvmem_config = { }; | ||
| 1013 | struct regmap *regmap; | ||
| 1014 | struct device *dev = &client->dev; | ||
| 1015 | int ret = 0; | ||
| 1016 | |||
| 1017 | nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); | ||
| 1018 | if (!nvm) | ||
| 1019 | return -ENOMEM; | ||
| 1020 | |||
| 1021 | regmap_config.val_bits = 8; | ||
| 1022 | regmap_config.reg_bits = 16; | ||
| 1023 | regmap_config.disable_locking = true; | ||
| 1024 | regmap = devm_regmap_init_i2c(client, ®map_config); | ||
| 1025 | if (IS_ERR(regmap)) | ||
| 1026 | return PTR_ERR(regmap); | ||
| 1027 | |||
| 1028 | nvm->regmap = regmap; | ||
| 1029 | |||
| 1030 | nvmem_config.name = dev_name(dev); | ||
| 1031 | nvmem_config.dev = dev; | ||
| 1032 | nvmem_config.read_only = true; | ||
| 1033 | nvmem_config.root_only = true; | ||
| 1034 | nvmem_config.owner = THIS_MODULE; | ||
| 1035 | nvmem_config.compat = true; | ||
| 1036 | nvmem_config.base_dev = dev; | ||
| 1037 | nvmem_config.reg_read = ov2740_nvmem_read; | ||
| 1038 | nvmem_config.reg_write = NULL; | ||
| 1039 | nvmem_config.priv = nvm; | ||
| 1040 | nvmem_config.stride = 1; | ||
| 1041 | nvmem_config.word_size = 1; | ||
| 1042 | nvmem_config.size = CUSTOMER_USE_OTP_SIZE; | ||
| 1043 | |||
| 1044 | nvm->nvmem = devm_nvmem_register(dev, &nvmem_config); | ||
| 1045 | if (IS_ERR(nvm->nvmem)) | ||
| 1046 | return PTR_ERR(nvm->nvmem); | ||
| 1047 | |||
| 1048 | nvm->nvm_buffer = devm_kzalloc(dev, CUSTOMER_USE_OTP_SIZE, GFP_KERNEL); | ||
| 1049 | if (!nvm->nvm_buffer) | ||
| 1050 | return -ENOMEM; | ||
| 1051 | |||
| 1052 | ret = ov2740_load_otp_data(client, nvm); | ||
| 1053 | if (ret) | ||
| 1054 | dev_err(dev, "failed to load OTP data, ret %d\n", ret); | ||
| 1055 | |||
| 1056 | return ret; | ||
| 1057 | } | ||
| 1058 | |||
| 918 | static int ov2740_probe(struct i2c_client *client) | 1059 | static int ov2740_probe(struct i2c_client *client) |
| 919 | { | 1060 | { |
| 920 | struct ov2740 *ov2740; | 1061 | struct ov2740 *ov2740; |
| @@ -964,6 +1105,10 @@ static int ov2740_probe(struct i2c_client *client) · 43 unmodified lines | |||
| 964 | goto probe_error_media_entity_cleanup; | 1105 | goto probe_error_media_entity_cleanup; |
| 965 | } | 1106 | } |
| 966 | 1107 | ||
| 1108 | ret = ov2740_register_nvmem(client); | ||
| 1109 | if (ret) | ||
| 1110 | dev_err(&client->dev, "register nvmem failed, ret %d\n", ret); | ||
| 1111 | |||
| 967 | /* | 1112 | /* |
| 968 | * Device is already turned on by i2c-core with ACPI domain PM. | 1113 | * Device is already turned on by i2c-core with ACPI domain PM. |
| 969 | * Enable runtime PM and turn off the device. | 1114 | * Enable runtime PM and turn off the device. |
| @@ -988,20 +1133,18 @@ static const struct dev_pm_ops ov2740_pm_ops = { · 18 unmodified lines | |||
| 988 | SET_SYSTEM_SLEEP_PM_OPS(ov2740_suspend, ov2740_resume) | 1133 | SET_SYSTEM_SLEEP_PM_OPS(ov2740_suspend, ov2740_resume) |
| 989 | }; | 1134 | }; |
| 990 | 1135 | ||
| 991 | #ifdef CONFIG_ACPI | ||
| 992 | static const struct acpi_device_id ov2740_acpi_ids[] = { | 1136 | static const struct acpi_device_id ov2740_acpi_ids[] = { |
| 993 | {"INT3474"}, | 1137 | {"INT3474"}, |
| 994 | {} | 1138 | {} |
| 995 | }; | 1139 | }; |
| 996 | 1140 | ||
| 997 | MODULE_DEVICE_TABLE(acpi, ov2740_acpi_ids); | 1141 | MODULE_DEVICE_TABLE(acpi, ov2740_acpi_ids); |
| 998 | #endif | ||
| 999 | 1142 | ||
| 1000 | static struct i2c_driver ov2740_i2c_driver = { | 1143 | static struct i2c_driver ov2740_i2c_driver = { |
| 1001 | .driver = { | 1144 | .driver = { |
| 1002 | .name = "ov2740", | 1145 | .name = "ov2740", |
| 1003 | .pm = &ov2740_pm_ops, | 1146 | .pm = &ov2740_pm_ops, |
| 1004 | .acpi_match_table = ACPI_PTR(ov2740_acpi_ids), | 1147 | .acpi_match_table = ov2740_acpi_ids, |
| 1005 | }, | 1148 | }, |
| 1006 | .probe_new = ov2740_probe, | 1149 | .probe_new = ov2740_probe, |
| 1007 | .remove = ov2740_remove, | 1150 | .remove = ov2740_remove, |
| @@ -772,6 +772,6 @@ static struct i2c_driver ov9640_i2c_driver = { · 771 unmodified lines | |||
| 772 | 772 | ||
| 773 | module_i2c_driver(ov9640_i2c_driver); | 773 | module_i2c_driver(ov9640_i2c_driver); |
| 774 | 774 | ||
| 775 | MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); | 775 | MODULE_DESCRIPTION("OmniVision OV96xx CMOS Image Sensor driver"); |
| 776 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | 776 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); |
| 777 | MODULE_LICENSE("GPL v2"); | 777 | MODULE_LICENSE("GPL v2"); |
| @@ -0,0 +1,667 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * IMI RDACM20 GMSL Camera Driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017-2020 Jacopo Mondi | ||
| 6 | * Copyright (C) 2017-2020 Kieran Bingham | ||
| 7 | * Copyright (C) 2017-2019 Laurent Pinchart | ||
| 8 | * Copyright (C) 2017-2019 Niklas Söderlund | ||
| 9 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
| 10 | * Copyright (C) 2015 Cogent Embedded, Inc. | ||
| 11 | */ | ||
| 12 | |||
| 13 | /* | ||
| 14 | * The camera is made of an Omnivision OV10635 sensor connected to a Maxim | ||
| 15 | * MAX9271 GMSL serializer. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/fwnode.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/i2c.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/videodev2.h> | ||
| 25 | |||
| 26 | #include <media/v4l2-async.h> | ||
| 27 | #include <media/v4l2-ctrls.h> | ||
| 28 | #include <media/v4l2-subdev.h> | ||
| 29 | |||
| 30 | #include "max9271.h" | ||
| 31 | |||
| 32 | #define OV10635_I2C_ADDRESS 0x30 | ||
| 33 | |||
| 34 | #define OV10635_SOFTWARE_RESET 0x0103 | ||
| 35 | #define OV10635_PID 0x300a | ||
| 36 | #define OV10635_VER 0x300b | ||
| 37 | #define OV10635_SC_CMMN_SCCB_ID 0x300c | ||
| 38 | #define OV10635_SC_CMMN_SCCB_ID_SELECT BIT(0) | ||
| 39 | #define OV10635_VERSION 0xa635 | ||
| 40 | |||
| 41 | #define OV10635_WIDTH 1280 | ||
| 42 | #define OV10635_HEIGHT 800 | ||
| 43 | |||
| 44 | /* VTS = PCLK / FPS / HTS / 2 (= 88MHz / 1572 / 30 / 2) */ | ||
| 45 | #define OV10635_HTS 1572 | ||
| 46 | /* FPS = 29,9998 */ | ||
| 47 | #define OV10635_VTS 933 | ||
| 48 | |||
| 49 | /* | ||
| 50 | * As the drivers supports a single MEDIA_BUS_FMT_UYVY8_2X8 format we | ||
| 51 | * can harcode the pixel rate. | ||
| 52 | * | ||
| 53 | * PCLK is fed through the system clock, programmed @88MHz. | ||
| 54 | * MEDIA_BUS_FMT_UYVY8_2X8 format = 2 samples per pixel. | ||
| 55 | * | ||
| 56 | * Pixelrate = PCLK / 2 | ||
| 57 | * FPS = (OV10635_VTS * OV10635_HTS) / PixelRate | ||
| 58 | * = 29,9998 | ||
| 59 | */ | ||
| 60 | #define OV10635_PIXEL_RATE (44000000) | ||
| 61 | |||
| 62 | static const struct ov10635_reg { | ||
| 63 | u16 reg; | ||
| 64 | u8 val; | ||
| 65 | } ov10635_regs_wizard[] = { | ||
| 66 | { 0x301b, 0xff }, { 0x301c, 0xff }, { 0x301a, 0xff }, { 0x3011, 0x42 }, | ||
| 67 | { 0x6900, 0x0c }, { 0x6901, 0x19 }, { 0x3503, 0x10 }, { 0x3025, 0x03 }, | ||
| 68 | { 0x3003, 0x16 }, { 0x3004, 0x30 }, { 0x3005, 0x40 }, { 0x3006, 0x91 }, | ||
| 69 | { 0x3600, 0x74 }, { 0x3601, 0x2b }, { 0x3612, 0x00 }, { 0x3611, 0x67 }, | ||
| 70 | { 0x3633, 0xca }, { 0x3602, 0xaf }, { 0x3603, 0x04 }, { 0x3630, 0x28 }, | ||
| 71 | { 0x3631, 0x16 }, { 0x3714, 0x10 }, { 0x371d, 0x01 }, { 0x4300, 0x3a }, | ||
| 72 | { 0x3007, 0x01 }, { 0x3024, 0x03 }, { 0x3020, 0x0a }, { 0x3702, 0x0d }, | ||
| 73 | { 0x3703, 0x20 }, { 0x3704, 0x15 }, { 0x3709, 0xa8 }, { 0x370c, 0xc7 }, | ||
| 74 | { 0x370d, 0x80 }, { 0x3712, 0x00 }, { 0x3713, 0x20 }, { 0x3715, 0x04 }, | ||
| 75 | { 0x381d, 0x40 }, { 0x381c, 0x00 }, { 0x3822, 0x50 }, { 0x3824, 0x10 }, | ||
| 76 | { 0x3815, 0x8c }, { 0x3804, 0x05 }, { 0x3805, 0x1f }, { 0x3800, 0x00 }, | ||
| 77 | { 0x3801, 0x00 }, { 0x3806, 0x03 }, { 0x3807, 0x28 }, { 0x3802, 0x00 }, | ||
| 78 | { 0x3803, 0x07 }, { 0x3808, 0x05 }, { 0x3809, 0x00 }, { 0x380a, 0x03 }, | ||
| 79 | { 0x380b, 0x20 }, { 0x380c, OV10635_HTS >> 8 }, | ||
| 80 | { 0x380d, OV10635_HTS & 0xff }, { 0x380e, OV10635_VTS >> 8 }, | ||
| 81 | { 0x380f, OV10635_VTS & 0xff }, { 0x3813, 0x02 }, { 0x3811, 0x08 }, | ||
| 82 | { 0x381f, 0x0c }, { 0x3819, 0x04 }, { 0x3804, 0x01 }, { 0x3805, 0x00 }, | ||
| 83 | { 0x3828, 0x03 }, { 0x3829, 0x10 }, { 0x382a, 0x10 }, { 0x3621, 0x63 }, | ||
| 84 | { 0x5005, 0x08 }, { 0x56d5, 0x00 }, { 0x56d6, 0x80 }, { 0x56d7, 0x00 }, | ||
| 85 | { 0x56d8, 0x00 }, { 0x56d9, 0x00 }, { 0x56da, 0x80 }, { 0x56db, 0x00 }, | ||
| 86 | { 0x56dc, 0x00 }, { 0x56e8, 0x00 }, { 0x56e9, 0x7f }, { 0x56ea, 0x00 }, | ||
| 87 | { 0x56eb, 0x7f }, { 0x5100, 0x00 }, { 0x5101, 0x80 }, { 0x5102, 0x00 }, | ||
| 88 | { 0x5103, 0x80 }, { 0x5104, 0x00 }, { 0x5105, 0x80 }, { 0x5106, 0x00 }, | ||
| 89 | { 0x5107, 0x80 }, { 0x5108, 0x00 }, { 0x5109, 0x00 }, { 0x510a, 0x00 }, | ||
| 90 | { 0x510b, 0x00 }, { 0x510c, 0x00 }, { 0x510d, 0x00 }, { 0x510e, 0x00 }, | ||
| 91 | { 0x510f, 0x00 }, { 0x5110, 0x00 }, { 0x5111, 0x80 }, { 0x5112, 0x00 }, | ||
| 92 | { 0x5113, 0x80 }, { 0x5114, 0x00 }, { 0x5115, 0x80 }, { 0x5116, 0x00 }, | ||
| 93 | { 0x5117, 0x80 }, { 0x5118, 0x00 }, { 0x5119, 0x00 }, { 0x511a, 0x00 }, | ||
| 94 | { 0x511b, 0x00 }, { 0x511c, 0x00 }, { 0x511d, 0x00 }, { 0x511e, 0x00 }, | ||
| 95 | { 0x511f, 0x00 }, { 0x56d0, 0x00 }, { 0x5006, 0x04 }, { 0x5608, 0x05 }, | ||
| 96 | { 0x52d7, 0x06 }, { 0x528d, 0x08 }, { 0x5293, 0x12 }, { 0x52d3, 0x12 }, | ||
| 97 | { 0x5288, 0x06 }, { 0x5289, 0x20 }, { 0x52c8, 0x06 }, { 0x52c9, 0x20 }, | ||
| 98 | { 0x52cd, 0x04 }, { 0x5381, 0x00 }, { 0x5382, 0xff }, { 0x5589, 0x76 }, | ||
| 99 | { 0x558a, 0x47 }, { 0x558b, 0xef }, { 0x558c, 0xc9 }, { 0x558d, 0x49 }, | ||
| 100 | { 0x558e, 0x30 }, { 0x558f, 0x67 }, { 0x5590, 0x3f }, { 0x5591, 0xf0 }, | ||
| 101 | { 0x5592, 0x10 }, { 0x55a2, 0x6d }, { 0x55a3, 0x55 }, { 0x55a4, 0xc3 }, | ||
| 102 | { 0x55a5, 0xb5 }, { 0x55a6, 0x43 }, { 0x55a7, 0x38 }, { 0x55a8, 0x5f }, | ||
| 103 | { 0x55a9, 0x4b }, { 0x55aa, 0xf0 }, { 0x55ab, 0x10 }, { 0x5581, 0x52 }, | ||
| 104 | { 0x5300, 0x01 }, { 0x5301, 0x00 }, { 0x5302, 0x00 }, { 0x5303, 0x0e }, | ||
| 105 | { 0x5304, 0x00 }, { 0x5305, 0x0e }, { 0x5306, 0x00 }, { 0x5307, 0x36 }, | ||
| 106 | { 0x5308, 0x00 }, { 0x5309, 0xd9 }, { 0x530a, 0x00 }, { 0x530b, 0x0f }, | ||
| 107 | { 0x530c, 0x00 }, { 0x530d, 0x2c }, { 0x530e, 0x00 }, { 0x530f, 0x59 }, | ||
| 108 | { 0x5310, 0x00 }, { 0x5311, 0x7b }, { 0x5312, 0x00 }, { 0x5313, 0x22 }, | ||
| 109 | { 0x5314, 0x00 }, { 0x5315, 0xd5 }, { 0x5316, 0x00 }, { 0x5317, 0x13 }, | ||
| 110 | { 0x5318, 0x00 }, { 0x5319, 0x18 }, { 0x531a, 0x00 }, { 0x531b, 0x26 }, | ||
| 111 | { 0x531c, 0x00 }, { 0x531d, 0xdc }, { 0x531e, 0x00 }, { 0x531f, 0x02 }, | ||
| 112 | { 0x5320, 0x00 }, { 0x5321, 0x24 }, { 0x5322, 0x00 }, { 0x5323, 0x56 }, | ||
| 113 | { 0x5324, 0x00 }, { 0x5325, 0x85 }, { 0x5326, 0x00 }, { 0x5327, 0x20 }, | ||
| 114 | { 0x5609, 0x01 }, { 0x560a, 0x40 }, { 0x560b, 0x01 }, { 0x560c, 0x40 }, | ||
| 115 | { 0x560d, 0x00 }, { 0x560e, 0xfa }, { 0x560f, 0x00 }, { 0x5610, 0xfa }, | ||
| 116 | { 0x5611, 0x02 }, { 0x5612, 0x80 }, { 0x5613, 0x02 }, { 0x5614, 0x80 }, | ||
| 117 | { 0x5615, 0x01 }, { 0x5616, 0x2c }, { 0x5617, 0x01 }, { 0x5618, 0x2c }, | ||
| 118 | { 0x563b, 0x01 }, { 0x563c, 0x01 }, { 0x563d, 0x01 }, { 0x563e, 0x01 }, | ||
| 119 | { 0x563f, 0x03 }, { 0x5640, 0x03 }, { 0x5641, 0x03 }, { 0x5642, 0x05 }, | ||
| 120 | { 0x5643, 0x09 }, { 0x5644, 0x05 }, { 0x5645, 0x05 }, { 0x5646, 0x05 }, | ||
| 121 | { 0x5647, 0x05 }, { 0x5651, 0x00 }, { 0x5652, 0x80 }, { 0x521a, 0x01 }, | ||
| 122 | { 0x521b, 0x03 }, { 0x521c, 0x06 }, { 0x521d, 0x0a }, { 0x521e, 0x0e }, | ||
| 123 | { 0x521f, 0x12 }, { 0x5220, 0x16 }, { 0x5223, 0x02 }, { 0x5225, 0x04 }, | ||
| 124 | { 0x5227, 0x08 }, { 0x5229, 0x0c }, { 0x522b, 0x12 }, { 0x522d, 0x18 }, | ||
| 125 | { 0x522f, 0x1e }, { 0x5241, 0x04 }, { 0x5242, 0x01 }, { 0x5243, 0x03 }, | ||
| 126 | { 0x5244, 0x06 }, { 0x5245, 0x0a }, { 0x5246, 0x0e }, { 0x5247, 0x12 }, | ||
| 127 | { 0x5248, 0x16 }, { 0x524a, 0x03 }, { 0x524c, 0x04 }, { 0x524e, 0x08 }, | ||
| 128 | { 0x5250, 0x0c }, { 0x5252, 0x12 }, { 0x5254, 0x18 }, { 0x5256, 0x1e }, | ||
| 129 | /* fifo_line_length = 2*hts */ | ||
| 130 | { 0x4606, (2 * OV10635_HTS) >> 8 }, { 0x4607, (2 * OV10635_HTS) & 0xff }, | ||
| 131 | /* fifo_hsync_start = 2*(hts - xres) */ | ||
| 132 | { 0x460a, (2 * (OV10635_HTS - OV10635_WIDTH)) >> 8 }, | ||
| 133 | { 0x460b, (2 * (OV10635_HTS - OV10635_WIDTH)) & 0xff }, | ||
| 134 | { 0x460c, 0x00 }, { 0x4620, 0x0e }, | ||
| 135 | /* BT601: 0x08 is also acceptable as HS/VS mode */ | ||
| 136 | { 0x4700, 0x04 }, { 0x4701, 0x00 }, { 0x4702, 0x01 }, { 0x4004, 0x04 }, | ||
| 137 | { 0x4005, 0x18 }, { 0x4001, 0x06 }, { 0x4050, 0x22 }, { 0x4051, 0x24 }, | ||
| 138 | { 0x4052, 0x02 }, { 0x4057, 0x9c }, { 0x405a, 0x00 }, { 0x4202, 0x02 }, | ||
| 139 | { 0x3023, 0x10 }, { 0x0100, 0x01 }, { 0x0100, 0x01 }, { 0x6f10, 0x07 }, | ||
| 140 | { 0x6f11, 0x82 }, { 0x6f12, 0x04 }, { 0x6f13, 0x00 }, { 0xd000, 0x19 }, | ||
| 141 | { 0xd001, 0xa0 }, { 0xd002, 0x00 }, { 0xd003, 0x01 }, { 0xd004, 0xa9 }, | ||
| 142 | { 0xd005, 0xad }, { 0xd006, 0x10 }, { 0xd007, 0x40 }, { 0xd008, 0x44 }, | ||
| 143 | { 0xd009, 0x00 }, { 0xd00a, 0x68 }, { 0xd00b, 0x00 }, { 0xd00c, 0x15 }, | ||
| 144 | { 0xd00d, 0x00 }, { 0xd00e, 0x00 }, { 0xd00f, 0x00 }, { 0xd040, 0x9c }, | ||
| 145 | { 0xd041, 0x21 }, { 0xd042, 0xff }, { 0xd043, 0xf8 }, { 0xd044, 0xd4 }, | ||
| 146 | { 0xd045, 0x01 }, { 0xd046, 0x48 }, { 0xd047, 0x00 }, { 0xd048, 0xd4 }, | ||
| 147 | { 0xd049, 0x01 }, { 0xd04a, 0x50 }, { 0xd04b, 0x04 }, { 0xd04c, 0x18 }, | ||
| 148 | { 0xd04d, 0x60 }, { 0xd04e, 0x00 }, { 0xd04f, 0x01 }, { 0xd050, 0xa8 }, | ||
| 149 | { 0xd051, 0x63 }, { 0xd052, 0x02 }, { 0xd053, 0xa4 }, { 0xd054, 0x85 }, | ||
| 150 | { 0xd055, 0x43 }, { 0xd056, 0x00 }, { 0xd057, 0x00 }, { 0xd058, 0x18 }, | ||
| 151 | { 0xd059, 0x60 }, { 0xd05a, 0x00 }, { 0xd05b, 0x01 }, { 0xd05c, 0xa8 }, | ||
| 152 | { 0xd05d, 0x63 }, { 0xd05e, 0x03 }, { 0xd05f, 0xf0 }, { 0xd060, 0x98 }, | ||
| 153 | { 0xd061, 0xa3 }, { 0xd062, 0x00 }, { 0xd063, 0x00 }, { 0xd064, 0x8c }, | ||
| 154 | { 0xd065, 0x6a }, { 0xd066, 0x00 }, { 0xd067, 0x6e }, { 0xd068, 0xe5 }, | ||
| 155 | { 0xd069, 0x85 }, { 0xd06a, 0x18 }, { 0xd06b, 0x00 }, { 0xd06c, 0x10 }, | ||
| 156 | { 0xd06d, 0x00 }, { 0xd06e, 0x00 }, { 0xd06f, 0x10 }, { 0xd070, 0x9c }, | ||
| 157 | { 0xd071, 0x80 }, { 0xd072, 0x00 }, { 0xd073, 0x03 }, { 0xd074, 0x18 }, | ||
| 158 | { 0xd075, 0x60 }, { 0xd076, 0x00 }, { 0xd077, 0x01 }, { 0xd078, 0xa8 }, | ||
| 159 | { 0xd079, 0x63 }, { 0xd07a, 0x07 }, { 0xd07b, 0x80 }, { 0xd07c, 0x07 }, | ||
| 160 | { 0xd07d, 0xff }, { 0xd07e, 0xf9 }, { 0xd07f, 0x03 }, { 0xd080, 0x8c }, | ||
| 161 | { 0xd081, 0x63 }, { 0xd082, 0x00 }, { 0xd083, 0x00 }, { 0xd084, 0xa5 }, | ||
| 162 | { 0xd085, 0x6b }, { 0xd086, 0x00 }, { 0xd087, 0xff }, { 0xd088, 0x18 }, | ||
| 163 | { 0xd089, 0x80 }, { 0xd08a, 0x00 }, { 0xd08b, 0x01 }, { 0xd08c, 0xa8 }, | ||
| 164 | { 0xd08d, 0x84 }, { 0xd08e, 0x01 }, { 0xd08f, 0x04 }, { 0xd090, 0xe1 }, | ||
| 165 | { 0xd091, 0x6b }, { 0xd092, 0x58 }, { 0xd093, 0x00 }, { 0xd094, 0x94 }, | ||
| 166 | { 0xd095, 0x6a }, { 0xd096, 0x00 }, { 0xd097, 0x70 }, { 0xd098, 0xe1 }, | ||
| 167 | { 0xd099, 0x6b }, { 0xd09a, 0x20 }, { 0xd09b, 0x00 }, { 0xd09c, 0x95 }, | ||
| 168 | { 0xd09d, 0x6b }, { 0xd09e, 0x00 }, { 0xd09f, 0x00 }, { 0xd0a0, 0xe4 }, | ||
| 169 | { 0xd0a1, 0x8b }, { 0xd0a2, 0x18 }, { 0xd0a3, 0x00 }, { 0xd0a4, 0x0c }, | ||
| 170 | { 0xd0a5, 0x00 }, { 0xd0a6, 0x00 }, { 0xd0a7, 0x23 }, { 0xd0a8, 0x15 }, | ||
| 171 | { 0xd0a9, 0x00 }, { 0xd0aa, 0x00 }, { 0xd0ab, 0x00 }, { 0xd0ac, 0x18 }, | ||
| 172 | { 0xd0ad, 0x60 }, { 0xd0ae, 0x80 }, { 0xd0af, 0x06 }, { 0xd0b0, 0xa8 }, | ||
| 173 | { 0xd0b1, 0x83 }, { 0xd0b2, 0x40 }, { 0xd0b3, 0x08 }, { 0xd0b4, 0xa8 }, | ||
| 174 | { 0xd0b5, 0xe3 }, { 0xd0b6, 0x38 }, { 0xd0b7, 0x2a }, { 0xd0b8, 0xa8 }, | ||
| 175 | { 0xd0b9, 0xc3 }, { 0xd0ba, 0x40 }, { 0xd0bb, 0x09 }, { 0xd0bc, 0xa8 }, | ||
| 176 | { 0xd0bd, 0xa3 }, { 0xd0be, 0x38 }, { 0xd0bf, 0x29 }, { 0xd0c0, 0x8c }, | ||
| 177 | { 0xd0c1, 0x65 }, { 0xd0c2, 0x00 }, { 0xd0c3, 0x00 }, { 0xd0c4, 0xd8 }, | ||
| 178 | { 0xd0c5, 0x04 }, { 0xd0c6, 0x18 }, { 0xd0c7, 0x00 }, { 0xd0c8, 0x8c }, | ||
| 179 | { 0xd0c9, 0x67 }, { 0xd0ca, 0x00 }, { 0xd0cb, 0x00 }, { 0xd0cc, 0xd8 }, | ||
| 180 | { 0xd0cd, 0x06 }, { 0xd0ce, 0x18 }, { 0xd0cf, 0x00 }, { 0xd0d0, 0x18 }, | ||
| 181 | { 0xd0d1, 0x60 }, { 0xd0d2, 0x80 }, { 0xd0d3, 0x06 }, { 0xd0d4, 0xa8 }, | ||
| 182 | { 0xd0d5, 0xe3 }, { 0xd0d6, 0x67 }, { 0xd0d7, 0x02 }, { 0xd0d8, 0xa9 }, | ||
| 183 | { 0xd0d9, 0x03 }, { 0xd0da, 0x67 }, { 0xd0db, 0x03 }, { 0xd0dc, 0xa8 }, | ||
| 184 | { 0xd0dd, 0xc3 }, { 0xd0de, 0x3d }, { 0xd0df, 0x05 }, { 0xd0e0, 0x8c }, | ||
| 185 | { 0xd0e1, 0x66 }, { 0xd0e2, 0x00 }, { 0xd0e3, 0x00 }, { 0xd0e4, 0xb8 }, | ||
| 186 | { 0xd0e5, 0x63 }, { 0xd0e6, 0x00 }, { 0xd0e7, 0x18 }, { 0xd0e8, 0xb8 }, | ||
| 187 | { 0xd0e9, 0x63 }, { 0xd0ea, 0x00 }, { 0xd0eb, 0x98 }, { 0xd0ec, 0xbc }, | ||
| 188 | { 0xd0ed, 0x03 }, { 0xd0ee, 0x00 }, { 0xd0ef, 0x00 }, { 0xd0f0, 0x10 }, | ||
| 189 | { 0xd0f1, 0x00 }, { 0xd0f2, 0x00 }, { 0xd0f3, 0x16 }, { 0xd0f4, 0xb8 }, | ||
| 190 | { 0xd0f5, 0x83 }, { 0xd0f6, 0x00 }, { 0xd0f7, 0x19 }, { 0xd0f8, 0x8c }, | ||
| 191 | { 0xd0f9, 0x67 }, { 0xd0fa, 0x00 }, { 0xd0fb, 0x00 }, { 0xd0fc, 0xb8 }, | ||
| 192 | { 0xd0fd, 0xa4 }, { 0xd0fe, 0x00 }, { 0xd0ff, 0x98 }, { 0xd100, 0xb8 }, | ||
| 193 | { 0xd101, 0x83 }, { 0xd102, 0x00 }, { 0xd103, 0x08 }, { 0xd104, 0x8c }, | ||
| 194 | { 0xd105, 0x68 }, { 0xd106, 0x00 }, { 0xd107, 0x00 }, { 0xd108, 0xe0 }, | ||
| 195 | { 0xd109, 0x63 }, { 0xd10a, 0x20 }, { 0xd10b, 0x04 }, { 0xd10c, 0xe0 }, | ||
| 196 | { 0xd10d, 0x65 }, { 0xd10e, 0x18 }, { 0xd10f, 0x00 }, { 0xd110, 0xa4 }, | ||
| 197 | { 0xd111, 0x83 }, { 0xd112, 0xff }, { 0xd113, 0xff }, { 0xd114, 0xb8 }, | ||
| 198 | { 0xd115, 0x64 }, { 0xd116, 0x00 }, { 0xd117, 0x48 }, { 0xd118, 0xd8 }, | ||
| 199 | { 0xd119, 0x07 }, { 0xd11a, 0x18 }, { 0xd11b, 0x00 }, { 0xd11c, 0xd8 }, | ||
| 200 | { 0xd11d, 0x08 }, { 0xd11e, 0x20 }, { 0xd11f, 0x00 }, { 0xd120, 0x9c }, | ||
| 201 | { 0xd121, 0x60 }, { 0xd122, 0x00 }, { 0xd123, 0x00 }, { 0xd124, 0xd8 }, | ||
| 202 | { 0xd125, 0x06 }, { 0xd126, 0x18 }, { 0xd127, 0x00 }, { 0xd128, 0x00 }, | ||
| 203 | { 0xd129, 0x00 }, { 0xd12a, 0x00 }, { 0xd12b, 0x08 }, { 0xd12c, 0x15 }, | ||
| 204 | { 0xd12d, 0x00 }, { 0xd12e, 0x00 }, { 0xd12f, 0x00 }, { 0xd130, 0x8c }, | ||
| 205 | { 0xd131, 0x6a }, { 0xd132, 0x00 }, { 0xd133, 0x76 }, { 0xd134, 0xbc }, | ||
| 206 | { 0xd135, 0x23 }, { 0xd136, 0x00 }, { 0xd137, 0x00 }, { 0xd138, 0x13 }, | ||
| 207 | { 0xd139, 0xff }, { 0xd13a, 0xff }, { 0xd13b, 0xe6 }, { 0xd13c, 0x18 }, | ||
| 208 | { 0xd13d, 0x60 }, { 0xd13e, 0x80 }, { 0xd13f, 0x06 }, { 0xd140, 0x03 }, | ||
| 209 | { 0xd141, 0xff }, { 0xd142, 0xff }, { 0xd143, 0xdd }, { 0xd144, 0xa8 }, | ||
| 210 | { 0xd145, 0x83 }, { 0xd146, 0x40 }, { 0xd147, 0x08 }, { 0xd148, 0x85 }, | ||
| 211 | { 0xd149, 0x21 }, { 0xd14a, 0x00 }, { 0xd14b, 0x00 }, { 0xd14c, 0x85 }, | ||
| 212 | { 0xd14d, 0x41 }, { 0xd14e, 0x00 }, { 0xd14f, 0x04 }, { 0xd150, 0x44 }, | ||
| 213 | { 0xd151, 0x00 }, { 0xd152, 0x48 }, { 0xd153, 0x00 }, { 0xd154, 0x9c }, | ||
| 214 | { 0xd155, 0x21 }, { 0xd156, 0x00 }, { 0xd157, 0x08 }, { 0x6f0e, 0x03 }, | ||
| 215 | { 0x6f0f, 0x00 }, { 0x460e, 0x08 }, { 0x460f, 0x01 }, { 0x4610, 0x00 }, | ||
| 216 | { 0x4611, 0x01 }, { 0x4612, 0x00 }, { 0x4613, 0x01 }, | ||
| 217 | /* 8 bits */ | ||
| 218 | { 0x4605, 0x08 }, | ||
| 219 | /* Swap data bits order [9:0] -> [0:9] */ | ||
| 220 | { 0x4709, 0x10 }, { 0x4608, 0x00 }, { 0x4609, 0x08 }, { 0x6804, 0x00 }, | ||
| 221 | { 0x6805, 0x06 }, { 0x6806, 0x00 }, { 0x5120, 0x00 }, { 0x3510, 0x00 }, | ||
| 222 | { 0x3504, 0x00 }, { 0x6800, 0x00 }, { 0x6f0d, 0x01 }, | ||
| 223 | /* PCLK falling edge */ | ||
| 224 | { 0x4708, 0x01 }, { 0x5000, 0xff }, { 0x5001, 0xbf }, { 0x5002, 0x7e }, | ||
| 225 | { 0x503d, 0x00 }, { 0xc450, 0x01 }, { 0xc452, 0x04 }, { 0xc453, 0x00 }, | ||
| 226 | { 0xc454, 0x00 }, { 0xc455, 0x01 }, { 0xc456, 0x01 }, { 0xc457, 0x00 }, | ||
| 227 | { 0xc458, 0x00 }, { 0xc459, 0x00 }, { 0xc45b, 0x00 }, { 0xc45c, 0x01 }, | ||
| 228 | { 0xc45d, 0x00 }, { 0xc45e, 0x00 }, { 0xc45f, 0x00 }, { 0xc460, 0x00 }, | ||
| 229 | { 0xc461, 0x01 }, { 0xc462, 0x01 }, { 0xc464, 0x03 }, { 0xc465, 0x00 }, | ||
| 230 | { 0xc466, 0x8a }, { 0xc467, 0x00 }, { 0xc468, 0x86 }, { 0xc469, 0x00 }, | ||
| 231 | { 0xc46a, 0x40 }, { 0xc46b, 0x50 }, { 0xc46c, 0x30 }, { 0xc46d, 0x28 }, | ||
| 232 | { 0xc46e, 0x60 }, { 0xc46f, 0x40 }, { 0xc47c, 0x01 }, { 0xc47d, 0x38 }, | ||
| 233 | { 0xc47e, 0x00 }, { 0xc47f, 0x00 }, { 0xc480, 0x00 }, { 0xc481, 0xff }, | ||
| 234 | { 0xc482, 0x00 }, { 0xc483, 0x40 }, { 0xc484, 0x00 }, { 0xc485, 0x18 }, | ||
| 235 | { 0xc486, 0x00 }, { 0xc487, 0x18 }, | ||
| 236 | { 0xc488, (OV10635_VTS - 8) * 16 >> 8}, | ||
| 237 | { 0xc489, (OV10635_VTS - 8) * 16 & 0xff}, | ||
| 238 | { 0xc48a, (OV10635_VTS - 8) * 16 >> 8}, | ||
| 239 | { 0xc48b, (OV10635_VTS - 8) * 16 & 0xff}, { 0xc48c, 0x00 }, | ||
| 240 | { 0xc48d, 0x04 }, { 0xc48e, 0x00 }, { 0xc48f, 0x04 }, { 0xc490, 0x03 }, | ||
| 241 | { 0xc492, 0x20 }, { 0xc493, 0x08 }, { 0xc498, 0x02 }, { 0xc499, 0x00 }, | ||
| 242 | { 0xc49a, 0x02 }, { 0xc49b, 0x00 }, { 0xc49c, 0x02 }, { 0xc49d, 0x00 }, | ||
| 243 | { 0xc49e, 0x02 }, { 0xc49f, 0x60 }, { 0xc4a0, 0x03 }, { 0xc4a1, 0x00 }, | ||
| 244 | { 0xc4a2, 0x04 }, { 0xc4a3, 0x00 }, { 0xc4a4, 0x00 }, { 0xc4a5, 0x10 }, | ||
| 245 | { 0xc4a6, 0x00 }, { 0xc4a7, 0x40 }, { 0xc4a8, 0x00 }, { 0xc4a9, 0x80 }, | ||
| 246 | { 0xc4aa, 0x0d }, { 0xc4ab, 0x00 }, { 0xc4ac, 0x0f }, { 0xc4ad, 0xc0 }, | ||
| 247 | { 0xc4b4, 0x01 }, { 0xc4b5, 0x01 }, { 0xc4b6, 0x00 }, { 0xc4b7, 0x01 }, | ||
| 248 | { 0xc4b8, 0x00 }, { 0xc4b9, 0x01 }, { 0xc4ba, 0x01 }, { 0xc4bb, 0x00 }, | ||
| 249 | { 0xc4bc, 0x01 }, { 0xc4bd, 0x60 }, { 0xc4be, 0x02 }, { 0xc4bf, 0x33 }, | ||
| 250 | { 0xc4c8, 0x03 }, { 0xc4c9, 0xd0 }, { 0xc4ca, 0x0e }, { 0xc4cb, 0x00 }, | ||
| 251 | { 0xc4cc, 0x0e }, { 0xc4cd, 0x51 }, { 0xc4ce, 0x0e }, { 0xc4cf, 0x51 }, | ||
| 252 | { 0xc4d0, 0x04 }, { 0xc4d1, 0x80 }, { 0xc4e0, 0x04 }, { 0xc4e1, 0x02 }, | ||
| 253 | { 0xc4e2, 0x01 }, { 0xc4e4, 0x10 }, { 0xc4e5, 0x20 }, { 0xc4e6, 0x30 }, | ||
| 254 | { 0xc4e7, 0x40 }, { 0xc4e8, 0x50 }, { 0xc4e9, 0x60 }, { 0xc4ea, 0x70 }, | ||
| 255 | { 0xc4eb, 0x80 }, { 0xc4ec, 0x90 }, { 0xc4ed, 0xa0 }, { 0xc4ee, 0xb0 }, | ||
| 256 | { 0xc4ef, 0xc0 }, { 0xc4f0, 0xd0 }, { 0xc4f1, 0xe0 }, { 0xc4f2, 0xf0 }, | ||
| 257 | { 0xc4f3, 0x80 }, { 0xc4f4, 0x00 }, { 0xc4f5, 0x20 }, { 0xc4f6, 0x02 }, | ||
| 258 | { 0xc4f7, 0x00 }, { 0xc4f8, 0x00 }, { 0xc4f9, 0x00 }, { 0xc4fa, 0x00 }, | ||
| 259 | { 0xc4fb, 0x01 }, { 0xc4fc, 0x01 }, { 0xc4fd, 0x00 }, { 0xc4fe, 0x04 }, | ||
| 260 | { 0xc4ff, 0x02 }, { 0xc500, 0x48 }, { 0xc501, 0x74 }, { 0xc502, 0x58 }, | ||
| 261 | { 0xc503, 0x80 }, { 0xc504, 0x05 }, { 0xc505, 0x80 }, { 0xc506, 0x03 }, | ||
| 262 | { 0xc507, 0x80 }, { 0xc508, 0x01 }, { 0xc509, 0xc0 }, { 0xc50a, 0x01 }, | ||
| 263 | { 0xc50b, 0xa0 }, { 0xc50c, 0x01 }, { 0xc50d, 0x2c }, { 0xc50e, 0x01 }, | ||
| 264 | { 0xc50f, 0x0a }, { 0xc510, 0x00 }, { 0xc511, 0x00 }, { 0xc512, 0xe5 }, | ||
| 265 | { 0xc513, 0x14 }, { 0xc514, 0x04 }, { 0xc515, 0x00 }, { 0xc518, OV10635_VTS >> 8}, | ||
| 266 | { 0xc519, OV10635_VTS & 0xff}, { 0xc51a, OV10635_HTS >> 8}, | ||
| 267 | { 0xc51b, OV10635_HTS & 0xff}, { 0xc2e0, 0x00 }, { 0xc2e1, 0x51 }, | ||
| 268 | { 0xc2e2, 0x00 }, { 0xc2e3, 0xd6 }, { 0xc2e4, 0x01 }, { 0xc2e5, 0x5e }, | ||
| 269 | { 0xc2e9, 0x01 }, { 0xc2ea, 0x7a }, { 0xc2eb, 0x90 }, { 0xc2ed, 0x00 }, | ||
| 270 | { 0xc2ee, 0x7a }, { 0xc2ef, 0x64 }, { 0xc308, 0x00 }, { 0xc309, 0x00 }, | ||
| 271 | { 0xc30a, 0x00 }, { 0xc30c, 0x00 }, { 0xc30d, 0x01 }, { 0xc30e, 0x00 }, | ||
| 272 | { 0xc30f, 0x00 }, { 0xc310, 0x01 }, { 0xc311, 0x60 }, { 0xc312, 0xff }, | ||
| 273 | { 0xc313, 0x08 }, { 0xc314, 0x01 }, { 0xc315, 0x00 }, { 0xc316, 0xff }, | ||
| 274 | { 0xc317, 0x0b }, { 0xc318, 0x00 }, { 0xc319, 0x0c }, { 0xc31a, 0x00 }, | ||
| 275 | { 0xc31b, 0xe0 }, { 0xc31c, 0x00 }, { 0xc31d, 0x14 }, { 0xc31e, 0x00 }, | ||
| 276 | { 0xc31f, 0xc5 }, { 0xc320, 0xff }, { 0xc321, 0x4b }, { 0xc322, 0xff }, | ||
| 277 | { 0xc323, 0xf0 }, { 0xc324, 0xff }, { 0xc325, 0xe8 }, { 0xc326, 0x00 }, | ||
| 278 | { 0xc327, 0x46 }, { 0xc328, 0xff }, { 0xc329, 0xd2 }, { 0xc32a, 0xff }, | ||
| 279 | { 0xc32b, 0xe4 }, { 0xc32c, 0xff }, { 0xc32d, 0xbb }, { 0xc32e, 0x00 }, | ||
| 280 | { 0xc32f, 0x61 }, { 0xc330, 0xff }, { 0xc331, 0xf9 }, { 0xc332, 0x00 }, | ||
| 281 | { 0xc333, 0xd9 }, { 0xc334, 0x00 }, { 0xc335, 0x2e }, { 0xc336, 0x00 }, | ||
| 282 | { 0xc337, 0xb1 }, { 0xc338, 0xff }, { 0xc339, 0x64 }, { 0xc33a, 0xff }, | ||
| 283 | { 0xc33b, 0xeb }, { 0xc33c, 0xff }, { 0xc33d, 0xe8 }, { 0xc33e, 0x00 }, | ||
| 284 | { 0xc33f, 0x48 }, { 0xc340, 0xff }, { 0xc341, 0xd0 }, { 0xc342, 0xff }, | ||
| 285 | { 0xc343, 0xed }, { 0xc344, 0xff }, { 0xc345, 0xad }, { 0xc346, 0x00 }, | ||
| 286 | { 0xc347, 0x66 }, { 0xc348, 0x01 }, { 0xc349, 0x00 }, { 0x6700, 0x04 }, | ||
| 287 | { 0x6701, 0x7b }, { 0x6702, 0xfd }, { 0x6703, 0xf9 }, { 0x6704, 0x3d }, | ||
| 288 | { 0x6705, 0x71 }, { 0x6706, 0x78 }, { 0x6708, 0x05 }, { 0x6f06, 0x6f }, | ||
| 289 | { 0x6f07, 0x00 }, { 0x6f0a, 0x6f }, { 0x6f0b, 0x00 }, { 0x6f00, 0x03 }, | ||
| 290 | { 0xc34c, 0x01 }, { 0xc34d, 0x00 }, { 0xc34e, 0x46 }, { 0xc34f, 0x55 }, | ||
| 291 | { 0xc350, 0x00 }, { 0xc351, 0x40 }, { 0xc352, 0x00 }, { 0xc353, 0xff }, | ||
| 292 | { 0xc354, 0x04 }, { 0xc355, 0x08 }, { 0xc356, 0x01 }, { 0xc357, 0xef }, | ||
| 293 | { 0xc358, 0x30 }, { 0xc359, 0x01 }, { 0xc35a, 0x64 }, { 0xc35b, 0x46 }, | ||
| 294 | { 0xc35c, 0x00 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, | ||
| 295 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, | ||
| 296 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, | ||
| 297 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, | ||
| 298 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, | ||
| 299 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, | ||
| 300 | { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0x3042, 0xf0 }, { 0xc261, 0x01 }, | ||
| 301 | { 0x301b, 0xf0 }, { 0x301c, 0xf0 }, { 0x301a, 0xf0 }, { 0x6f00, 0xc3 }, | ||
| 302 | { 0xc46a, 0x30 }, { 0xc46d, 0x20 }, { 0xc464, 0x84 }, { 0xc465, 0x00 }, | ||
| 303 | { 0x6f00, 0x03 }, { 0x6f00, 0x43 }, { 0x381c, 0x00 }, { 0x381d, 0x40 }, | ||
| 304 | { 0xc454, 0x01 }, { 0x6f00, 0xc3 }, { 0xc454, 0x00 }, { 0xc4b1, 0x02 }, | ||
| 305 | { 0xc4b2, 0x01 }, { 0xc4b3, 0x03 }, { 0x6f00, 0x03 }, { 0x6f00, 0x43 }, | ||
| 306 | /* enable FSIN (FRAMESYNC input) functionality */ | ||
| 307 | { 0x3832, (0x0d + 2 * 0x20 + 0x15 + 38) >> 8 }, | ||
| 308 | { 0x3833, (0x0d + 2 * 0x20 + 0x15 + 38) & 0xff }, | ||
| 309 | { 0x3834, OV10635_VTS >> 8 }, { 0x3835, OV10635_VTS & 0xff }, | ||
| 310 | { 0x302e, 0x01 }, | ||
| 311 | }; | ||
| 312 | |||
| 313 | struct rdacm20_device { | ||
| 314 | struct device *dev; | ||
| 315 | struct max9271_device *serializer; | ||
| 316 | struct i2c_client *sensor; | ||
| 317 | struct v4l2_subdev sd; | ||
| 318 | struct media_pad pad; | ||
| 319 | struct v4l2_ctrl_handler ctrls; | ||
| 320 | u32 addrs[2]; | ||
| 321 | }; | ||
| 322 | |||
| 323 | static inline struct rdacm20_device *sd_to_rdacm20(struct v4l2_subdev *sd) | ||
| 324 | { | ||
| 325 | return container_of(sd, struct rdacm20_device, sd); | ||
| 326 | } | ||
| 327 | |||
| 328 | static inline struct rdacm20_device *i2c_to_rdacm20(struct i2c_client *client) | ||
| 329 | { | ||
| 330 | return sd_to_rdacm20(i2c_get_clientdata(client)); | ||
| 331 | } | ||
| 332 | |||
| 333 | static int ov10635_read16(struct rdacm20_device *dev, u16 reg) | ||
| 334 | { | ||
| 335 | u8 buf[2] = { reg >> 8, reg & 0xff }; | ||
| 336 | int ret; | ||
| 337 | |||
| 338 | ret = i2c_master_send(dev->sensor, buf, 2); | ||
| 339 | if (ret != 2) { | ||
| 340 | dev_dbg(dev->dev, "%s: register 0x%04x write failed (%d)\n", | ||
| 341 | __func__, reg, ret); | ||
| 342 | return ret; | ||
| 343 | } | ||
| 344 | |||
| 345 | ret = i2c_master_recv(dev->sensor, buf, 2); | ||
| 346 | if (ret < 0) { | ||
| 347 | dev_dbg(dev->dev, "%s: register 0x%04x read failed (%d)\n", | ||
| 348 | __func__, reg, ret); | ||
| 349 | return ret; | ||
| 350 | } | ||
| 351 | |||
| 352 | return (buf[0] << 8) | buf[1]; | ||
| 353 | } | ||
| 354 | |||
| 355 | static int __ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val) | ||
| 356 | { | ||
| 357 | u8 buf[3] = { reg >> 8, reg & 0xff, val }; | ||
| 358 | int ret; | ||
| 359 | |||
| 360 | dev_dbg(dev->dev, "%s(0x%04x, 0x%02x)\n", __func__, reg, val); | ||
| 361 | |||
| 362 | ret = i2c_master_send(dev->sensor, buf, 3); | ||
| 363 | return ret < 0 ? ret : 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | static int ov10635_write(struct rdacm20_device *dev, u16 reg, u8 val) | ||
| 367 | { | ||
| 368 | int ret; | ||
| 369 | |||
| 370 | ret = __ov10635_write(dev, reg, val); | ||
| 371 | if (ret < 0) | ||
| 372 | dev_err(dev->dev, "%s: register 0x%04x write failed (%d)\n", | ||
| 373 | __func__, reg, ret); | ||
| 374 | |||
| 375 | return ret; | ||
| 376 | } | ||
| 377 | |||
| 378 | static int ov10635_set_regs(struct rdacm20_device *dev, | ||
| 379 | const struct ov10635_reg *regs, | ||
| 380 | unsigned int nr_regs) | ||
| 381 | { | ||
| 382 | unsigned int i; | ||
| 383 | int ret; | ||
| 384 | |||
| 385 | for (i = 0; i < nr_regs; i++) { | ||
| 386 | ret = __ov10635_write(dev, regs[i].reg, regs[i].val); | ||
| 387 | if (ret) { | ||
| 388 | dev_err(dev->dev, | ||
| 389 | "%s: register %u (0x%04x) write failed (%d)\n", | ||
| 390 | __func__, i, regs[i].reg, ret); | ||
| 391 | return ret; | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | |||
| 398 | static int rdacm20_s_stream(struct v4l2_subdev *sd, int enable) | ||
| 399 | { | ||
| 400 | struct rdacm20_device *dev = sd_to_rdacm20(sd); | ||
| 401 | |||
| 402 | return max9271_set_serial_link(dev->serializer, enable); | ||
| 403 | } | ||
| 404 | |||
| 405 | static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd, | ||
| 406 | struct v4l2_subdev_pad_config *cfg, | ||
| 407 | struct v4l2_subdev_mbus_code_enum *code) | ||
| 408 | { | ||
| 409 | if (code->pad || code->index > 0) | ||
| 410 | return -EINVAL; | ||
| 411 | |||
| 412 | code->code = MEDIA_BUS_FMT_UYVY8_2X8; | ||
| 413 | |||
| 414 | return 0; | ||
| 415 | } | ||
| 416 | |||
| 417 | static int rdacm20_get_fmt(struct v4l2_subdev *sd, | ||
| 418 | struct v4l2_subdev_pad_config *cfg, | ||
| 419 | struct v4l2_subdev_format *format) | ||
| 420 | { | ||
| 421 | struct v4l2_mbus_framefmt *mf = &format->format; | ||
| 422 | |||
| 423 | if (format->pad) | ||
| 424 | return -EINVAL; | ||
| 425 | |||
| 426 | mf->width = OV10635_WIDTH; | ||
| 427 | mf->height = OV10635_HEIGHT; | ||
| 428 | mf->code = MEDIA_BUS_FMT_UYVY8_2X8; | ||
| 429 | mf->colorspace = V4L2_COLORSPACE_RAW; | ||
| 430 | mf->field = V4L2_FIELD_NONE; | ||
| 431 | mf->ycbcr_enc = V4L2_YCBCR_ENC_601; | ||
| 432 | mf->quantization = V4L2_QUANTIZATION_FULL_RANGE; | ||
| 433 | mf->xfer_func = V4L2_XFER_FUNC_NONE; | ||
| 434 | |||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | static struct v4l2_subdev_video_ops rdacm20_video_ops = { | ||
| 439 | .s_stream = rdacm20_s_stream, | ||
| 440 | }; | ||
| 441 | |||
| 442 | static const struct v4l2_subdev_pad_ops rdacm20_subdev_pad_ops = { | ||
| 443 | .enum_mbus_code = rdacm20_enum_mbus_code, | ||
| 444 | .get_fmt = rdacm20_get_fmt, | ||
| 445 | .set_fmt = rdacm20_get_fmt, | ||
| 446 | }; | ||
| 447 | |||
| 448 | static struct v4l2_subdev_ops rdacm20_subdev_ops = { | ||
| 449 | .video = &rdacm20_video_ops, | ||
| 450 | .pad = &rdacm20_subdev_pad_ops, | ||
| 451 | }; | ||
| 452 | |||
| 453 | static int rdacm20_initialize(struct rdacm20_device *dev) | ||
| 454 | { | ||
| 455 | unsigned int retry = 3; | ||
| 456 | int ret; | ||
| 457 | |||
| 458 | /* Verify communication with the MAX9271: ping to wakeup. */ | ||
| 459 | dev->serializer->client->addr = MAX9271_DEFAULT_ADDR; | ||
| 460 | i2c_smbus_read_byte(dev->serializer->client); | ||
| 461 | |||
| 462 | /* Serial link disabled during config as it needs a valid pixel clock. */ | ||
| 463 | ret = max9271_set_serial_link(dev->serializer, false); | ||
| 464 | if (ret) | ||
| 465 | return ret; | ||
| 466 | |||
| 467 | /* | ||
| 468 | * Ensure that we have a good link configuration before attempting to | ||
| 469 | * identify the device. | ||
| 470 | */ | ||
| 471 | max9271_configure_i2c(dev->serializer, MAX9271_I2CSLVSH_469NS_234NS | | ||
| 472 | MAX9271_I2CSLVTO_1024US | | ||
| 473 | MAX9271_I2CMSTBT_105KBPS); | ||
| 474 | |||
| 475 | max9271_configure_gmsl_link(dev->serializer); | ||
| 476 | |||
| 477 | ret = max9271_verify_id(dev->serializer); | ||
| 478 | if (ret < 0) | ||
| 479 | return ret; | ||
| 480 | |||
| 481 | ret = max9271_set_address(dev->serializer, dev->addrs[0]); | ||
| 482 | if (ret < 0) | ||
| 483 | return ret; | ||
| 484 | dev->serializer->client->addr = dev->addrs[0]; | ||
| 485 | |||
| 486 | /* | ||
| 487 | * Reset the sensor by cycling the OV10635 reset signal connected to the | ||
| 488 | * MAX9271 GPIO1 and verify communication with the OV10635. | ||
| 489 | */ | ||
| 490 | max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT); | ||
| 491 | usleep_range(10000, 15000); | ||
| 492 | max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT); | ||
| 493 | usleep_range(10000, 15000); | ||
| 494 | |||
| 495 | again: | ||
| 496 | ret = ov10635_read16(dev, OV10635_PID); | ||
| 497 | if (ret < 0) { | ||
| 498 | if (retry--) | ||
| 499 | goto again; | ||
| 500 | |||
| 501 | dev_err(dev->dev, "OV10635 ID read failed (%d)\n", | ||
| 502 | ret); | ||
| 503 | return -ENXIO; | ||
| 504 | } | ||
| 505 | |||
| 506 | if (ret != OV10635_VERSION) { | ||
| 507 | if (retry--) | ||
| 508 | goto again; | ||
| 509 | |||
| 510 | dev_err(dev->dev, "OV10635 ID mismatch (0x%04x)\n", | ||
| 511 | ret); | ||
| 512 | return -ENXIO; | ||
| 513 | } | ||
| 514 | |||
| 515 | /* Change the sensor I2C address. */ | ||
| 516 | ret = ov10635_write(dev, OV10635_SC_CMMN_SCCB_ID, | ||
| 517 | (dev->addrs[1] << 1) | | ||
| 518 | OV10635_SC_CMMN_SCCB_ID_SELECT); | ||
| 519 | if (ret < 0) { | ||
| 520 | dev_err(dev->dev, | ||
| 521 | "OV10635 I2C address change failed (%d)\n", ret); | ||
| 522 | return ret; | ||
| 523 | } | ||
| 524 | dev->sensor->addr = dev->addrs[1]; | ||
| 525 | usleep_range(3500, 5000); | ||
| 526 | |||
| 527 | /* Program the 0V10635 initial configuration. */ | ||
| 528 | ret = ov10635_set_regs(dev, ov10635_regs_wizard, | ||
| 529 | ARRAY_SIZE(ov10635_regs_wizard)); | ||
| 530 | if (ret) | ||
| 531 | return ret; | ||
| 532 | |||
| 533 | dev_info(dev->dev, "Identified MAX9271 + OV10635 device\n"); | ||
| 534 | |||
| 535 | return 0; | ||
| 536 | } | ||
| 537 | |||
| 538 | static int rdacm20_probe(struct i2c_client *client) | ||
| 539 | { | ||
| 540 | struct rdacm20_device *dev; | ||
| 541 | struct fwnode_handle *ep; | ||
| 542 | int ret; | ||
| 543 | |||
| 544 | dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); | ||
| 545 | if (!dev) | ||
| 546 | return -ENOMEM; | ||
| 547 | dev->dev = &client->dev; | ||
| 548 | |||
| 549 | dev->serializer = devm_kzalloc(&client->dev, sizeof(*dev->serializer), | ||
| 550 | GFP_KERNEL); | ||
| 551 | if (!dev->serializer) | ||
| 552 | return -ENOMEM; | ||
| 553 | |||
| 554 | dev->serializer->client = client; | ||
| 555 | |||
| 556 | ret = of_property_read_u32_array(client->dev.of_node, "reg", | ||
| 557 | dev->addrs, 2); | ||
| 558 | if (ret < 0) { | ||
| 559 | dev_err(dev->dev, "Invalid DT reg property: %d\n", ret); | ||
| 560 | return -EINVAL; | ||
| 561 | } | ||
| 562 | |||
| 563 | /* Create the dummy I2C client for the sensor. */ | ||
| 564 | dev->sensor = i2c_new_dummy_device(client->adapter, | ||
| 565 | OV10635_I2C_ADDRESS); | ||
| 566 | if (IS_ERR(dev->sensor)) { | ||
| 567 | ret = PTR_ERR(dev->sensor); | ||
| 568 | goto error; | ||
| 569 | } | ||
| 570 | |||
| 571 | /* Initialize the hardware. */ | ||
| 572 | ret = rdacm20_initialize(dev); | ||
| 573 | if (ret < 0) | ||
| 574 | goto error; | ||
| 575 | |||
| 576 | /* Initialize and register the subdevice. */ | ||
| 577 | v4l2_i2c_subdev_init(&dev->sd, client, &rdacm20_subdev_ops); | ||
| 578 | dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 579 | |||
| 580 | v4l2_ctrl_handler_init(&dev->ctrls, 1); | ||
| 581 | v4l2_ctrl_new_std(&dev->ctrls, NULL, V4L2_CID_PIXEL_RATE, | ||
| 582 | OV10635_PIXEL_RATE, OV10635_PIXEL_RATE, 1, | ||
| 583 | OV10635_PIXEL_RATE); | ||
| 584 | dev->sd.ctrl_handler = &dev->ctrls; | ||
| 585 | |||
| 586 | ret = dev->ctrls.error; | ||
| 587 | if (ret) | ||
| 588 | goto error_free_ctrls; | ||
| 589 | |||
| 590 | dev->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
| 591 | dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; | ||
| 592 | ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); | ||
| 593 | if (ret < 0) | ||
| 594 | goto error_free_ctrls; | ||
| 595 | |||
| 596 | ep = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); | ||
| 597 | if (!ep) { | ||
| 598 | dev_err(&client->dev, | ||
| 599 | "Unable to get endpoint in node %pOF\n", | ||
| 600 | client->dev.of_node); | ||
| 601 | ret = -ENOENT; | ||
| 602 | goto error_free_ctrls; | ||
| 603 | } | ||
| 604 | dev->sd.fwnode = ep; | ||
| 605 | |||
| 606 | ret = v4l2_async_register_subdev(&dev->sd); | ||
| 607 | if (ret) | ||
| 608 | goto error_put_node; | ||
| 609 | |||
| 610 | return 0; | ||
| 611 | |||
| 612 | error_put_node: | ||
| 613 | fwnode_handle_put(ep); | ||
| 614 | error_free_ctrls: | ||
| 615 | v4l2_ctrl_handler_free(&dev->ctrls); | ||
| 616 | error: | ||
| 617 | media_entity_cleanup(&dev->sd.entity); | ||
| 618 | if (dev->sensor) | ||
| 619 | i2c_unregister_device(dev->sensor); | ||
| 620 | |||
| 621 | dev_err(&client->dev, "probe failed\n"); | ||
| 622 | |||
| 623 | return ret; | ||
| 624 | } | ||
| 625 | |||
| 626 | static int rdacm20_remove(struct i2c_client *client) | ||
| 627 | { | ||
| 628 | struct rdacm20_device *dev = i2c_to_rdacm20(client); | ||
| 629 | |||
| 630 | fwnode_handle_put(dev->sd.fwnode); | ||
| 631 | v4l2_async_unregister_subdev(&dev->sd); | ||
| 632 | v4l2_ctrl_handler_free(&dev->ctrls); | ||
| 633 | media_entity_cleanup(&dev->sd.entity); | ||
| 634 | i2c_unregister_device(dev->sensor); | ||
| 635 | |||
| 636 | return 0; | ||
| 637 | } | ||
| 638 | |||
| 639 | static void rdacm20_shutdown(struct i2c_client *client) | ||
| 640 | { | ||
| 641 | struct rdacm20_device *dev = i2c_to_rdacm20(client); | ||
| 642 | |||
| 643 | /* make sure stream off during shutdown (reset/reboot) */ | ||
| 644 | rdacm20_s_stream(&dev->sd, 0); | ||
| 645 | } | ||
| 646 | |||
| 647 | static const struct of_device_id rdacm20_of_ids[] = { | ||
| 648 | { .compatible = "imi,rdacm20", }, | ||
| 649 | { } | ||
| 650 | }; | ||
| 651 | MODULE_DEVICE_TABLE(of, rdacm20_of_ids); | ||
| 652 | |||
| 653 | static struct i2c_driver rdacm20_i2c_driver = { | ||
| 654 | .driver = { | ||
| 655 | .name = "rdacm20", | ||
| 656 | .of_match_table = rdacm20_of_ids, | ||
| 657 | }, | ||
| 658 | .probe_new = rdacm20_probe, | ||
| 659 | .remove = rdacm20_remove, | ||
| 660 | .shutdown = rdacm20_shutdown, | ||
| 661 | }; | ||
| 662 | |||
| 663 | module_i2c_driver(rdacm20_i2c_driver); | ||
| 664 | |||
| 665 | MODULE_DESCRIPTION("GMSL Camera driver for RDACM20"); | ||
| 666 | MODULE_AUTHOR("Vladimir Barinov"); | ||
| 667 | MODULE_LICENSE("GPL"); | ||
| @@ -197,7 +197,7 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor) · 196 unmodified lines | |||
| 197 | 197 | ||
| 198 | ret = pm_runtime_get(sensor->dev); | 198 | ret = pm_runtime_get(sensor->dev); |
| 199 | if (ret < 0) | 199 | if (ret < 0) |
| 200 | return ret; | 200 | goto error_rpm_put; |
| 201 | 201 | ||
| 202 | ret = regulator_enable(sensor->supplies[i].consumer); | 202 | ret = regulator_enable(sensor->supplies[i].consumer); |
| 203 | if (ret < 0) | 203 | if (ret < 0) |
| @@ -508,9 +508,7 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) · 507 unmodified lines | |||
| 508 | break; | 508 | break; |
| 509 | } | 509 | } |
| 510 | 510 | ||
| 511 | pm_runtime_get_noresume(&client->dev); | 511 | pm_status = pm_runtime_get_if_active(&client->dev, true); |
| 512 | pm_status = pm_runtime_get_if_in_use(&client->dev); | ||
| 513 | pm_runtime_put_noidle(&client->dev); | ||
| 514 | if (!pm_status) | 512 | if (!pm_status) |
| 515 | return 0; | 513 | return 0; |
| 516 | 514 | ||
| @@ -3103,6 +3101,7 @@ static int smiapp_probe(struct i2c_client *client) · 2586 unmodified lines | |||
| 3103 | return 0; | 3101 | return 0; |
| 3104 | 3102 | ||
| 3105 | out_disable_runtime_pm: | 3103 | out_disable_runtime_pm: |
| 3104 | pm_runtime_put_noidle(&client->dev); | ||
| 3106 | pm_runtime_disable(&client->dev); | 3105 | pm_runtime_disable(&client->dev); |
| 3107 | 3106 | ||
| 3108 | out_media_entity_cleanup: | 3107 | out_media_entity_cleanup: |
| @@ -1664,8 +1664,10 @@ static int tvp5150_registered(struct v4l2_subdev *sd) · 1663 unmodified lines | |||
| 1664 | return 0; | 1664 | return 0; |
| 1665 | 1665 | ||
| 1666 | err: | 1666 | err: |
| 1667 | for (i = 0; i < decoder->connectors_num; i++) | 1667 | for (i = 0; i < decoder->connectors_num; i++) { |
| 1668 | media_device_unregister_entity(&decoder->connectors[i].ent); | 1668 | media_device_unregister_entity(&decoder->connectors[i].ent); |
| 1669 | media_entity_cleanup(&decoder->connectors[i].ent); | ||
| 1670 | } | ||
| 1669 | return ret; | 1671 | return ret; |
| 1670 | #endif | 1672 | #endif |
| 1671 | 1673 | ||
| @@ -2248,8 +2250,10 @@ static int tvp5150_remove(struct i2c_client *c) · 576 unmodified lines | |||
| 2248 | 2250 | ||
| 2249 | for (i = 0; i < decoder->connectors_num; i++) | 2251 | for (i = 0; i < decoder->connectors_num; i++) |
| 2250 | v4l2_fwnode_connector_free(&decoder->connectors[i].base); | 2252 | v4l2_fwnode_connector_free(&decoder->connectors[i].base); |
| 2251 | for (i = 0; i < decoder->connectors_num; i++) | 2253 | for (i = 0; i < decoder->connectors_num; i++) { |
| 2252 | media_device_unregister_entity(&decoder->connectors[i].ent); | 2254 | media_device_unregister_entity(&decoder->connectors[i].ent); |
| 2255 | media_entity_cleanup(&decoder->connectors[i].ent); | ||
| 2256 | } | ||
| 2253 | v4l2_async_unregister_subdev(sd); | 2257 | v4l2_async_unregister_subdev(sd); |
| 2254 | v4l2_ctrl_handler_free(&decoder->hdl); | 2258 | v4l2_ctrl_handler_free(&decoder->hdl); |
| 2255 | pm_runtime_disable(&c->dev); | 2259 | pm_runtime_disable(&c->dev); |
| @@ -296,9 +296,18 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) · 295 unmodified lines | |||
| 296 | if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free)) | 296 | if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free)) |
| 297 | return -ENOMEM; | 297 | return -ENOMEM; |
| 298 | 298 | ||
| 299 | if (mdev->ops->req_alloc) | ||
| 300 | req = mdev->ops->req_alloc(mdev); | ||
| 301 | else | ||
| 302 | req = kzalloc(sizeof(*req), GFP_KERNEL); | ||
| 303 | if (!req) | ||
| 304 | return -ENOMEM; | ||
| 305 | |||
| 299 | fd = get_unused_fd_flags(O_CLOEXEC); | 306 | fd = get_unused_fd_flags(O_CLOEXEC); |
| 300 | if (fd < 0) | 307 | if (fd < 0) { |
| 301 | return fd; | 308 | ret = fd; |
| 309 | goto err_free_req; | ||
| 310 | } | ||
| 302 | 311 | ||
| 303 | filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC); | 312 | filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC); |
| 304 | if (IS_ERR(filp)) { | 313 | if (IS_ERR(filp)) { |
| @@ -306,15 +315,6 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) · 1 unmodified line | |||
| 306 | goto err_put_fd; | 315 | goto err_put_fd; |
| 307 | } | 316 | } |
| 308 | 317 | ||
| 309 | if (mdev->ops->req_alloc) | ||
| 310 | req = mdev->ops->req_alloc(mdev); | ||
| 311 | else | ||
| 312 | req = kzalloc(sizeof(*req), GFP_KERNEL); | ||
| 313 | if (!req) { | ||
| 314 | ret = -ENOMEM; | ||
| 315 | goto err_fput; | ||
| 316 | } | ||
| 317 | |||
| 318 | filp->private_data = req; | 318 | filp->private_data = req; |
| 319 | req->mdev = mdev; | 319 | req->mdev = mdev; |
| 320 | req->state = MEDIA_REQUEST_STATE_IDLE; | 320 | req->state = MEDIA_REQUEST_STATE_IDLE; |
| @@ -336,12 +336,15 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) · 15 unmodified lines | |||
| 336 | 336 | ||
| 337 | return 0; | 337 | return 0; |
| 338 | 338 | ||
| 339 | err_fput: | ||
| 340 | fput(filp); | ||
| 341 | |||
| 342 | err_put_fd: | 339 | err_put_fd: |
| 343 | put_unused_fd(fd); | 340 | put_unused_fd(fd); |
| 344 | 341 | ||
| 342 | err_free_req: | ||
| 343 | if (mdev->ops->req_free) | ||
| 344 | mdev->ops->req_free(req); | ||
| 345 | else | ||
| 346 | kfree(req); | ||
| 347 | |||
| 345 | return ret; | 348 | return ret; |
| 346 | } | 349 | } |
| 347 | 350 | ||
| @@ -35,7 +35,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_nxp = { · 34 unmodified lines | |||
| 35 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, | 35 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/ | 38 | /* Please add new PCI IDs to: https://pci-ids.ucw.cz/ |
| 39 | This keeps the PCI ID database up to date. Note that the entries | 39 | This keeps the PCI ID database up to date. Note that the entries |
| 40 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. | 40 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. |
| 41 | New vendor IDs should still be added to the vendor ID list. */ | 41 | New vendor IDs should still be added to the vendor ID list. */ |
| @@ -2235,9 +2235,6 @@ static struct pci_driver cx23885_pci_driver = { · 2234 unmodified lines | |||
| 2235 | .id_table = cx23885_pci_tbl, | 2235 | .id_table = cx23885_pci_tbl, |
| 2236 | .probe = cx23885_initdev, | 2236 | .probe = cx23885_initdev, |
| 2237 | .remove = cx23885_finidev, | 2237 | .remove = cx23885_finidev, |
| 2238 | /* TODO */ | ||
| 2239 | .suspend = NULL, | ||
| 2240 | .resume = NULL, | ||
| 2241 | }; | 2238 | }; |
| 2242 | 2239 | ||
| 2243 | static int __init cx23885_init(void) | 2240 | static int __init cx23885_init(void) |
| @@ -175,19 +175,6 @@ static inline u16 count_to_clock_divider(unsigned int d) · 174 unmodified lines | |||
| 175 | return (u16) d; | 175 | return (u16) d; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | static inline u16 ns_to_clock_divider(unsigned int ns) | ||
| 179 | { | ||
| 180 | return count_to_clock_divider( | ||
| 181 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); | ||
| 182 | } | ||
| 183 | |||
| 184 | static inline unsigned int clock_divider_to_ns(unsigned int divider) | ||
| 185 | { | ||
| 186 | /* Period of the Rx or Tx clock in ns */ | ||
| 187 | return DIV_ROUND_CLOSEST((divider + 1) * 1000, | ||
| 188 | CX23888_IR_REFCLK_FREQ / 1000000); | ||
| 189 | } | ||
| 190 | |||
| 191 | static inline u16 carrier_freq_to_clock_divider(unsigned int freq) | 178 | static inline u16 carrier_freq_to_clock_divider(unsigned int freq) |
| 192 | { | 179 | { |
| 193 | return count_to_clock_divider( | 180 | return count_to_clock_divider( |
| @@ -199,13 +186,6 @@ static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) · 5 unmodified lines | |||
| 199 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16); | 186 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16); |
| 200 | } | 187 | } |
| 201 | 188 | ||
| 202 | static inline u16 freq_to_clock_divider(unsigned int freq, | ||
| 203 | unsigned int rollovers) | ||
| 204 | { | ||
| 205 | return count_to_clock_divider( | ||
| 206 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers)); | ||
| 207 | } | ||
| 208 | |||
| 209 | static inline unsigned int clock_divider_to_freq(unsigned int divider, | 189 | static inline unsigned int clock_divider_to_freq(unsigned int divider, |
| 210 | unsigned int rollovers) | 190 | unsigned int rollovers) |
| 211 | { | 191 | { |
| @@ -1374,9 +1374,6 @@ static struct pci_driver cx25821_pci_driver = { · 1373 unmodified lines | |||
| 1374 | .id_table = cx25821_pci_tbl, | 1374 | .id_table = cx25821_pci_tbl, |
| 1375 | .probe = cx25821_initdev, | 1375 | .probe = cx25821_initdev, |
| 1376 | .remove = cx25821_finidev, | 1376 | .remove = cx25821_finidev, |
| 1377 | /* TODO */ | ||
| 1378 | .suspend = NULL, | ||
| 1379 | .resume = NULL, | ||
| 1380 | }; | 1377 | }; |
| 1381 | 1378 | ||
| 1382 | static int __init cx25821_init(void) | 1379 | static int __init cx25821_init(void) |
| @@ -385,8 +385,7 @@ static int start_video_dma(struct cx8800_dev *dev, · 384 unmodified lines | |||
| 385 | return 0; | 385 | return 0; |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | #ifdef CONFIG_PM | 388 | static int __maybe_unused stop_video_dma(struct cx8800_dev *dev) |
| 389 | static int stop_video_dma(struct cx8800_dev *dev) | ||
| 390 | { | 389 | { |
| 391 | struct cx88_core *core = dev->core; | 390 | struct cx88_core *core = dev->core; |
| 392 | 391 | ||
| @@ -402,8 +401,8 @@ static int stop_video_dma(struct cx8800_dev *dev) · 9 unmodified lines | |||
| 402 | return 0; | 401 | return 0; |
| 403 | } | 402 | } |
| 404 | 403 | ||
| 405 | static int restart_video_queue(struct cx8800_dev *dev, | 404 | static int __maybe_unused restart_video_queue(struct cx8800_dev *dev, |
| 406 | struct cx88_dmaqueue *q) | 405 | struct cx88_dmaqueue *q) |
| 407 | { | 406 | { |
| 408 | struct cx88_buffer *buf; | 407 | struct cx88_buffer *buf; |
| 409 | 408 | ||
| @@ -415,7 +414,6 @@ static int restart_video_queue(struct cx8800_dev *dev, · 5 unmodified lines | |||
| 415 | } | 414 | } |
| 416 | return 0; | 415 | return 0; |
| 417 | } | 416 | } |
| 418 | #endif | ||
| 419 | 417 | ||
| 420 | /* ------------------------------------------------------------------ */ | 418 | /* ------------------------------------------------------------------ */ |
| 421 | 419 | ||
| @@ -1551,10 +1549,9 @@ static void cx8800_finidev(struct pci_dev *pci_dev) · 1129 unmodified lines | |||
| 1551 | kfree(dev); | 1549 | kfree(dev); |
| 1552 | } | 1550 | } |
| 1553 | 1551 | ||
| 1554 | #ifdef CONFIG_PM | 1552 | static int __maybe_unused cx8800_suspend(struct device *dev_d) |
| 1555 | static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) | ||
| 1556 | { | 1553 | { |
| 1557 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | 1554 | struct cx8800_dev *dev = dev_get_drvdata(dev_d); |
| 1558 | struct cx88_core *core = dev->core; | 1555 | struct cx88_core *core = dev->core; |
| 1559 | unsigned long flags; | 1556 | unsigned long flags; |
| 1560 | 1557 | ||
| @@ -1575,40 +1572,17 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) · 14 unmodified lines | |||
| 1575 | /* FIXME -- shutdown device */ | 1572 | /* FIXME -- shutdown device */ |
| 1576 | cx88_shutdown(core); | 1573 | cx88_shutdown(core); |
| 1577 | 1574 | ||
| 1578 | pci_save_state(pci_dev); | 1575 | dev->state.disabled = 1; |
| 1579 | if (pci_set_power_state(pci_dev, | ||
| 1580 | pci_choose_state(pci_dev, state)) != 0) { | ||
| 1581 | pci_disable_device(pci_dev); | ||
| 1582 | dev->state.disabled = 1; | ||
| 1583 | } | ||
| 1584 | return 0; | 1576 | return 0; |
| 1585 | } | 1577 | } |
| 1586 | 1578 | ||
| 1587 | static int cx8800_resume(struct pci_dev *pci_dev) | 1579 | static int __maybe_unused cx8800_resume(struct device *dev_d) |
| 1588 | { | 1580 | { |
| 1589 | struct cx8800_dev *dev = pci_get_drvdata(pci_dev); | 1581 | struct cx8800_dev *dev = dev_get_drvdata(dev_d); |
| 1590 | struct cx88_core *core = dev->core; | 1582 | struct cx88_core *core = dev->core; |
| 1591 | unsigned long flags; | 1583 | unsigned long flags; |
| 1592 | int err; | ||
| 1593 | 1584 | ||
| 1594 | if (dev->state.disabled) { | 1585 | dev->state.disabled = 0; |
| 1595 | err = pci_enable_device(pci_dev); | ||
| 1596 | if (err) { | ||
| 1597 | pr_err("can't enable device\n"); | ||
| 1598 | return err; | ||
| 1599 | } | ||
| 1600 | |||
| 1601 | dev->state.disabled = 0; | ||
| 1602 | } | ||
| 1603 | err = pci_set_power_state(pci_dev, PCI_D0); | ||
| 1604 | if (err) { | ||
| 1605 | pr_err("can't set power state\n"); | ||
| 1606 | pci_disable_device(pci_dev); | ||
| 1607 | dev->state.disabled = 1; | ||
| 1608 | |||
| 1609 | return err; | ||
| 1610 | } | ||
| 1611 | pci_restore_state(pci_dev); | ||
| 1612 | 1586 | ||
| 1613 | /* FIXME: re-initialize hardware */ | 1587 | /* FIXME: re-initialize hardware */ |
| 1614 | cx88_reset(core); | 1588 | cx88_reset(core); |
| @@ -1631,7 +1605,6 @@ static int cx8800_resume(struct pci_dev *pci_dev) · 16 unmodified lines | |||
| 1631 | 1605 | ||
| 1632 | return 0; | 1606 | return 0; |
| 1633 | } | 1607 | } |
| 1634 | #endif | ||
| 1635 | 1608 | ||
| 1636 | /* ----------------------------------------------------------- */ | 1609 | /* ----------------------------------------------------------- */ |
| 1637 | 1610 | ||
| @@ -1647,15 +1620,14 @@ static const struct pci_device_id cx8800_pci_tbl[] = { · 9 unmodified lines | |||
| 1647 | }; | 1620 | }; |
| 1648 | MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl); | 1621 | MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl); |
| 1649 | 1622 | ||
| 1623 | static SIMPLE_DEV_PM_OPS(cx8800_pm_ops, cx8800_suspend, cx8800_resume); | ||
| 1624 | |||
| 1650 | static struct pci_driver cx8800_pci_driver = { | 1625 | static struct pci_driver cx8800_pci_driver = { |
| 1651 | .name = "cx8800", | 1626 | .name = "cx8800", |
| 1652 | .id_table = cx8800_pci_tbl, | 1627 | .id_table = cx8800_pci_tbl, |
| 1653 | .probe = cx8800_initdev, | 1628 | .probe = cx8800_initdev, |
| 1654 | .remove = cx8800_finidev, | 1629 | .remove = cx8800_finidev, |
| 1655 | #ifdef CONFIG_PM | 1630 | .driver.pm = &cx8800_pm_ops, |
| 1656 | .suspend = cx8800_suspend, | ||
| 1657 | .resume = cx8800_resume, | ||
| 1658 | #endif | ||
| 1659 | }; | 1631 | }; |
| 1660 | 1632 | ||
| 1661 | module_pci_driver(cx8800_pci_driver); | 1633 | module_pci_driver(cx8800_pci_driver); |
| @@ -426,7 +426,7 @@ static int dt3155_init_board(struct dt3155_priv *pd) · 425 unmodified lines | |||
| 426 | iowrite32(FIFO_EN | SRST, pd->regs + CSR1); | 426 | iowrite32(FIFO_EN | SRST, pd->regs + CSR1); |
| 427 | iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT); | 427 | iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT); |
| 428 | iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT); | 428 | iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT); |
| 429 | iowrite32(0x00000020, pd->regs + FIFO_TRIGER); | 429 | iowrite32(0x00000020, pd->regs + FIFO_TRIGGER); |
| 430 | iowrite32(0x00000103, pd->regs + XFER_MODE); | 430 | iowrite32(0x00000103, pd->regs + XFER_MODE); |
| 431 | iowrite32(0, pd->regs + RETRY_WAIT_CNT); | 431 | iowrite32(0, pd->regs + RETRY_WAIT_CNT); |
| 432 | iowrite32(0, pd->regs + INT_CSR); | 432 | iowrite32(0, pd->regs + INT_CSR); |
| @@ -31,7 +31,7 @@ · 30 unmodified lines | |||
| 31 | #define ODD_DMA_STRIDE 0x24 | 31 | #define ODD_DMA_STRIDE 0x24 |
| 32 | #define EVEN_PIXEL_FMT 0x30 | 32 | #define EVEN_PIXEL_FMT 0x30 |
| 33 | #define ODD_PIXEL_FMT 0x34 | 33 | #define ODD_PIXEL_FMT 0x34 |
| 34 | #define FIFO_TRIGER 0x38 | 34 | #define FIFO_TRIGGER 0x38 |
| 35 | #define XFER_MODE 0x3C | 35 | #define XFER_MODE 0x3C |
| 36 | #define CSR1 0x40 | 36 | #define CSR1 0x40 |
| 37 | #define RETRY_WAIT_CNT 0x44 | 37 | #define RETRY_WAIT_CNT 0x44 |
| @@ -53,7 +53,7 @@ static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = { · 52 unmodified lines | |||
| 53 | 53 | ||
| 54 | /********************** card configuration *******************************/ | 54 | /********************** card configuration *******************************/ |
| 55 | 55 | ||
| 56 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/ | 56 | /* Please add new PCI IDs to: https://pci-ids.ucw.cz/ |
| 57 | This keeps the PCI ID database up to date. Note that the entries | 57 | This keeps the PCI ID database up to date. Note that the entries |
| 58 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. | 58 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. |
| 59 | New vendor IDs should still be added to the vendor ID list. */ | 59 | New vendor IDs should still be added to the vendor ID list. */ |
| @@ -1528,19 +1528,16 @@ static const struct v4l2_ctrl_ops meye_ctrl_ops = { · 1527 unmodified lines | |||
| 1528 | .s_ctrl = meye_s_ctrl, | 1528 | .s_ctrl = meye_s_ctrl, |
| 1529 | }; | 1529 | }; |
| 1530 | 1530 | ||
| 1531 | #ifdef CONFIG_PM | 1531 | static int __maybe_unused meye_suspend(struct device *dev) |
| 1532 | static int meye_suspend(struct pci_dev *pdev, pm_message_t state) | ||
| 1533 | { | 1532 | { |
| 1534 | pci_save_state(pdev); | ||
| 1535 | meye.pm_mchip_mode = meye.mchip_mode; | 1533 | meye.pm_mchip_mode = meye.mchip_mode; |
| 1536 | mchip_hic_stop(); | 1534 | mchip_hic_stop(); |
| 1537 | mchip_set(MCHIP_MM_INTA, 0x0); | 1535 | mchip_set(MCHIP_MM_INTA, 0x0); |
| 1538 | return 0; | 1536 | return 0; |
| 1539 | } | 1537 | } |
| 1540 | 1538 | ||
| 1541 | static int meye_resume(struct pci_dev *pdev) | 1539 | static int __maybe_unused meye_resume(struct device *dev) |
| 1542 | { | 1540 | { |
| 1543 | pci_restore_state(pdev); | ||
| 1544 | pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); | 1541 | pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); |
| 1545 | 1542 | ||
| 1546 | mchip_delay(MCHIP_HIC_CMD, 0); | 1543 | mchip_delay(MCHIP_HIC_CMD, 0); |
| @@ -1562,7 +1559,6 @@ static int meye_resume(struct pci_dev *pdev) · 15 unmodified lines | |||
| 1562 | } | 1559 | } |
| 1563 | return 0; | 1560 | return 0; |
| 1564 | } | 1561 | } |
| 1565 | #endif | ||
| 1566 | 1562 | ||
| 1567 | static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) | 1563 | static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) |
| 1568 | { | 1564 | { |
| @@ -1788,15 +1784,14 @@ static const struct pci_device_id meye_pci_tbl[] = { · 219 unmodified lines | |||
| 1788 | 1784 | ||
| 1789 | MODULE_DEVICE_TABLE(pci, meye_pci_tbl); | 1785 | MODULE_DEVICE_TABLE(pci, meye_pci_tbl); |
| 1790 | 1786 | ||
| 1787 | static SIMPLE_DEV_PM_OPS(meye_pm_ops, meye_suspend, meye_resume); | ||
| 1788 | |||
| 1791 | static struct pci_driver meye_driver = { | 1789 | static struct pci_driver meye_driver = { |
| 1792 | .name = "meye", | 1790 | .name = "meye", |
| 1793 | .id_table = meye_pci_tbl, | 1791 | .id_table = meye_pci_tbl, |
| 1794 | .probe = meye_probe, | 1792 | .probe = meye_probe, |
| 1795 | .remove = meye_remove, | 1793 | .remove = meye_remove, |
| 1796 | #ifdef CONFIG_PM | 1794 | .driver.pm = &meye_pm_ops, |
| 1797 | .suspend = meye_suspend, | ||
| 1798 | .resume = meye_resume, | ||
| 1799 | #endif | ||
| 1800 | }; | 1795 | }; |
| 1801 | 1796 | ||
| 1802 | static int __init meye_init(void) | 1797 | static int __init meye_init(void) |
| @@ -305,9 +305,7 @@ struct meye { · 304 unmodified lines | |||
| 305 | u16 colour; | 305 | u16 colour; |
| 306 | struct meye_params params; /* additional parameters */ | 306 | struct meye_params params; /* additional parameters */ |
| 307 | unsigned long in_use; /* set to 1 if the device is in use */ | 307 | unsigned long in_use; /* set to 1 if the device is in use */ |
| 308 | #ifdef CONFIG_PM | ||
| 309 | u8 pm_mchip_mode; /* old mchip mode */ | 308 | u8 pm_mchip_mode; /* old mchip mode */ |
| 310 | #endif | ||
| 311 | }; | 309 | }; |
| 312 | 310 | ||
| 313 | #endif | 311 | #endif |
| @@ -1539,9 +1539,6 @@ static struct pci_driver saa7164_pci_driver = { · 1538 unmodified lines | |||
| 1539 | .id_table = saa7164_pci_tbl, | 1539 | .id_table = saa7164_pci_tbl, |
| 1540 | .probe = saa7164_initdev, | 1540 | .probe = saa7164_initdev, |
| 1541 | .remove = saa7164_finidev, | 1541 | .remove = saa7164_finidev, |
| 1542 | /* TODO */ | ||
| 1543 | .suspend = NULL, | ||
| 1544 | .resume = NULL, | ||
| 1545 | }; | 1542 | }; |
| 1546 | 1543 | ||
| 1547 | static int __init saa7164_init(void) | 1544 | static int __init saa7164_init(void) |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1,6 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com> | 3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
| 4 | * | 4 | * |
| 5 | * Original author: | 5 | * Original author: |
| 6 | * Ben Collins <bcollins@ubuntu.com> | 6 | * Ben Collins <bcollins@ubuntu.com> |
| @@ -1167,21 +1167,18 @@ static void sta2x11_vip_remove_one(struct pci_dev *pdev) · 1166 unmodified lines | |||
| 1167 | */ | 1167 | */ |
| 1168 | } | 1168 | } |
| 1169 | 1169 | ||
| 1170 | #ifdef CONFIG_PM | ||
| 1171 | |||
| 1172 | /** | 1170 | /** |
| 1173 | * sta2x11_vip_suspend - set device into power save mode | 1171 | * sta2x11_vip_suspend - set device into power save mode |
| 1174 | * @pdev: PCI device | 1172 | * @dev_d: PCI device |
| 1175 | * @state: new state of device | ||
| 1176 | * | 1173 | * |
| 1177 | * all relevant registers are saved and an attempt to set a new state is made. | 1174 | * all relevant registers are saved and an attempt to set a new state is made. |
| 1178 | * | 1175 | * |
| 1179 | * return value: 0 always indicate success, | 1176 | * return value: 0 always indicate success, |
| 1180 | * even if device could not be disabled. (workaround for hardware problem) | 1177 | * even if device could not be disabled. (workaround for hardware problem) |
| 1181 | */ | 1178 | */ |
| 1182 | static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state) | 1179 | static int __maybe_unused sta2x11_vip_suspend(struct device *dev_d) |
| 1183 | { | 1180 | { |
| 1184 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); | 1181 | struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d); |
| 1185 | struct sta2x11_vip *vip = | 1182 | struct sta2x11_vip *vip = |
| 1186 | container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev); | 1183 | container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev); |
| 1187 | unsigned long flags; | 1184 | unsigned long flags; |
| @@ -1198,15 +1195,8 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state) · 10 unmodified lines | |||
| 1198 | vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] = | 1195 | vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] = |
| 1199 | reg_read(vip, registers_to_save[i]); | 1196 | reg_read(vip, registers_to_save[i]); |
| 1200 | spin_unlock_irqrestore(&vip->slock, flags); | 1197 | spin_unlock_irqrestore(&vip->slock, flags); |
| 1201 | /* save pci state */ | 1198 | |
| 1202 | pci_save_state(pdev); | 1199 | vip->disabled = 1; |
| 1203 | if (pci_set_power_state(pdev, pci_choose_state(pdev, state))) { | ||
| 1204 | /* | ||
| 1205 | * do not call pci_disable_device on sta2x11 because it | ||
| 1206 | * break all other Bus masters on this EP | ||
| 1207 | */ | ||
| 1208 | vip->disabled = 1; | ||
| 1209 | } | ||
| 1210 | 1200 | ||
| 1211 | pr_info("VIP: suspend\n"); | 1201 | pr_info("VIP: suspend\n"); |
| 1212 | return 0; | 1202 | return 0; |
| @@ -1214,45 +1204,23 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state) · 1 unmodified line | |||
| 1214 | 1204 | ||
| 1215 | /** | 1205 | /** |
| 1216 | * sta2x11_vip_resume - resume device operation | 1206 | * sta2x11_vip_resume - resume device operation |
| 1217 | * @pdev : PCI device | 1207 | * @dev_d : PCI device |
| 1218 | * | ||
| 1219 | * re-enable device, set PCI state to powered and restore registers. | ||
| 1220 | * resume normal device operation afterwards. | ||
| 1221 | * | 1208 | * |
| 1222 | * return value: 0, no error. | 1209 | * return value: 0, no error. |
| 1223 | * | 1210 | * |
| 1224 | * other, could not set device to power on state. | 1211 | * other, could not set device to power on state. |
| 1225 | */ | 1212 | */ |
| 1226 | static int sta2x11_vip_resume(struct pci_dev *pdev) | 1213 | static int __maybe_unused sta2x11_vip_resume(struct device *dev_d) |
| 1227 | { | 1214 | { |
| 1228 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); | 1215 | struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d); |
| 1229 | struct sta2x11_vip *vip = | 1216 | struct sta2x11_vip *vip = |
| 1230 | container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev); | 1217 | container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev); |
| 1231 | unsigned long flags; | 1218 | unsigned long flags; |
| 1232 | int ret, i; | 1219 | int i; |
| 1233 | 1220 | ||
| 1234 | pr_info("VIP: resume\n"); | 1221 | pr_info("VIP: resume\n"); |
| 1235 | /* restore pci state */ | ||
| 1236 | if (vip->disabled) { | ||
| 1237 | ret = pci_enable_device(pdev); | ||
| 1238 | if (ret) { | ||
| 1239 | pr_warn("VIP: Can't enable device.\n"); | ||
| 1240 | return ret; | ||
| 1241 | } | ||
| 1242 | vip->disabled = 0; | ||
| 1243 | } | ||
| 1244 | ret = pci_set_power_state(pdev, PCI_D0); | ||
| 1245 | if (ret) { | ||
| 1246 | /* | ||
| 1247 | * do not call pci_disable_device on sta2x11 because it | ||
| 1248 | * break all other Bus masters on this EP | ||
| 1249 | */ | ||
| 1250 | pr_warn("VIP: Can't enable device.\n"); | ||
| 1251 | vip->disabled = 1; | ||
| 1252 | return ret; | ||
| 1253 | } | ||
| 1254 | 1222 | ||
| 1255 | pci_restore_state(pdev); | 1223 | vip->disabled = 0; |
| 1256 | 1224 | ||
| 1257 | spin_lock_irqsave(&vip->slock, flags); | 1225 | spin_lock_irqsave(&vip->slock, flags); |
| 1258 | for (i = 1; i < SAVE_COUNT; i++) | 1226 | for (i = 1; i < SAVE_COUNT; i++) |
| @@ -1266,22 +1234,21 @@ static int sta2x11_vip_resume(struct pci_dev *pdev) · 7 unmodified lines | |||
| 1266 | return 0; | 1234 | return 0; |
| 1267 | } | 1235 | } |
| 1268 | 1236 | ||
| 1269 | #endif | ||
| 1270 | |||
| 1271 | static const struct pci_device_id sta2x11_vip_pci_tbl[] = { | 1237 | static const struct pci_device_id sta2x11_vip_pci_tbl[] = { |
| 1272 | {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)}, | 1238 | {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)}, |
| 1273 | {0,} | 1239 | {0,} |
| 1274 | }; | 1240 | }; |
| 1275 | 1241 | ||
| 1242 | static SIMPLE_DEV_PM_OPS(sta2x11_vip_pm_ops, | ||
| 1243 | sta2x11_vip_suspend, | ||
| 1244 | sta2x11_vip_resume); | ||
| 1245 | |||
| 1276 | static struct pci_driver sta2x11_vip_driver = { | 1246 | static struct pci_driver sta2x11_vip_driver = { |
| 1277 | .name = KBUILD_MODNAME, | 1247 | .name = KBUILD_MODNAME, |
| 1278 | .probe = sta2x11_vip_init_one, | 1248 | .probe = sta2x11_vip_init_one, |
| 1279 | .remove = sta2x11_vip_remove_one, | 1249 | .remove = sta2x11_vip_remove_one, |
| 1280 | .id_table = sta2x11_vip_pci_tbl, | 1250 | .id_table = sta2x11_vip_pci_tbl, |
| 1281 | #ifdef CONFIG_PM | 1251 | .driver.pm = &sta2x11_vip_pm_ops, |
| 1282 | .suspend = sta2x11_vip_suspend, | ||
| 1283 | .resume = sta2x11_vip_resume, | ||
| 1284 | #endif | ||
| 1285 | }; | 1252 | }; |
| 1286 | 1253 | ||
| 1287 | static int __init sta2x11_vip_init_module(void) | 1254 | static int __init sta2x11_vip_init_module(void) |
| @@ -406,14 +406,15 @@ static void debiirq(unsigned long cookie) · 405 unmodified lines | |||
| 406 | case DATA_CI_GET: | 406 | case DATA_CI_GET: |
| 407 | { | 407 | { |
| 408 | u8 *data = av7110->debi_virt; | 408 | u8 *data = av7110->debi_virt; |
| 409 | u8 data_0 = data[0]; | ||
| 409 | 410 | ||
| 410 | if ((data[0] < 2) && data[2] == 0xff) { | 411 | if (data_0 < 2 && data[2] == 0xff) { |
| 411 | int flags = 0; | 412 | int flags = 0; |
| 412 | if (data[5] > 0) | 413 | if (data[5] > 0) |
| 413 | flags |= CA_CI_MODULE_PRESENT; | 414 | flags |= CA_CI_MODULE_PRESENT; |
| 414 | if (data[5] > 5) | 415 | if (data[5] > 5) |
| 415 | flags |= CA_CI_MODULE_READY; | 416 | flags |= CA_CI_MODULE_READY; |
| 416 | av7110->ci_slot[data[0]].flags = flags; | 417 | av7110->ci_slot[data_0].flags = flags; |
| 417 | } else | 418 | } else |
| 418 | ci_get_data(&av7110->ci_rbuffer, | 419 | ci_get_data(&av7110->ci_rbuffer, |
| 419 | av7110->debi_virt, | 420 | av7110->debi_virt, |
| @@ -369,20 +369,25 @@ static int budget_register(struct budget *budget) · 368 unmodified lines | |||
| 369 | ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend); | 369 | ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend); |
| 370 | 370 | ||
| 371 | if (ret < 0) | 371 | if (ret < 0) |
| 372 | return ret; | 372 | goto err_release_dmx; |
| 373 | 373 | ||
| 374 | budget->mem_frontend.source = DMX_MEMORY_FE; | 374 | budget->mem_frontend.source = DMX_MEMORY_FE; |
| 375 | ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); | 375 | ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); |
| 376 | if (ret < 0) | 376 | if (ret < 0) |
| 377 | return ret; | 377 | goto err_release_dmx; |
| 378 | 378 | ||
| 379 | ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); | 379 | ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); |
| 380 | if (ret < 0) | 380 | if (ret < 0) |
| 381 | return ret; | 381 | goto err_release_dmx; |
| 382 | 382 | ||
| 383 | dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); | 383 | dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); |
| 384 | 384 | ||
| 385 | return 0; | 385 | return 0; |
| 386 | |||
| 387 | err_release_dmx: | ||
| 388 | dvb_dmxdev_release(&budget->dmxdev); | ||
| 389 | dvb_dmx_release(&budget->demux); | ||
| 390 | return ret; | ||
| 386 | } | 391 | } |
| 387 | 392 | ||
| 388 | static void budget_unregister(struct budget *budget) | 393 | static void budget_unregister(struct budget *budget) |
| @@ -65,7 +65,7 @@ module_param_array(video_nr, int, NULL, 0444); · 64 unmodified lines | |||
| 65 | MODULE_PARM_DESC(video_nr, "video devices numbers array"); | 65 | MODULE_PARM_DESC(video_nr, "video devices numbers array"); |
| 66 | 66 | ||
| 67 | /* | 67 | /* |
| 68 | * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps | 68 | * Please add any new PCI IDs to: https://pci-ids.ucw.cz. This keeps |
| 69 | * the PCI ID database up to date. Note that the entries must be | 69 | * the PCI ID database up to date. Note that the entries must be |
| 70 | * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. | 70 | * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. |
| 71 | */ | 71 | */ |
| @@ -57,7 +57,7 @@ static atomic_t tw68_instance = ATOMIC_INIT(0); · 56 unmodified lines | |||
| 57 | /* ------------------------------------------------------------------ */ | 57 | /* ------------------------------------------------------------------ */ |
| 58 | 58 | ||
| 59 | /* | 59 | /* |
| 60 | * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps | 60 | * Please add any new PCI IDs to: https://pci-ids.ucw.cz. This keeps |
| 61 | * the PCI ID database up to date. Note that the entries must be | 61 | * the PCI ID database up to date. Note that the entries must be |
| 62 | * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. | 62 | * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. |
| 63 | */ | 63 | */ |
| @@ -359,10 +359,9 @@ static void tw68_finidev(struct pci_dev *pci_dev) · 295 unmodified lines | |||
| 359 | v4l2_device_unregister(&dev->v4l2_dev); | 359 | v4l2_device_unregister(&dev->v4l2_dev); |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | #ifdef CONFIG_PM | 362 | static int __maybe_unused tw68_suspend(struct device *dev_d) |
| 363 | |||
| 364 | static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) | ||
| 365 | { | 363 | { |
| 364 | struct pci_dev *pci_dev = to_pci_dev(dev_d); | ||
| 366 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | 365 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); |
| 367 | struct tw68_dev *dev = container_of(v4l2_dev, | 366 | struct tw68_dev *dev = container_of(v4l2_dev, |
| 368 | struct tw68_dev, v4l2_dev); | 367 | struct tw68_dev, v4l2_dev); |
| @@ -373,24 +372,19 @@ static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) · 4 unmodified lines | |||
| 373 | 372 | ||
| 374 | synchronize_irq(pci_dev->irq); | 373 | synchronize_irq(pci_dev->irq); |
| 375 | 374 | ||
| 376 | pci_save_state(pci_dev); | ||
| 377 | pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); | ||
| 378 | vb2_discard_done(&dev->vidq); | 375 | vb2_discard_done(&dev->vidq); |
| 379 | 376 | ||
| 380 | return 0; | 377 | return 0; |
| 381 | } | 378 | } |
| 382 | 379 | ||
| 383 | static int tw68_resume(struct pci_dev *pci_dev) | 380 | static int __maybe_unused tw68_resume(struct device *dev_d) |
| 384 | { | 381 | { |
| 385 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | 382 | struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d); |
| 386 | struct tw68_dev *dev = container_of(v4l2_dev, | 383 | struct tw68_dev *dev = container_of(v4l2_dev, |
| 387 | struct tw68_dev, v4l2_dev); | 384 | struct tw68_dev, v4l2_dev); |
| 388 | struct tw68_buf *buf; | 385 | struct tw68_buf *buf; |
| 389 | unsigned long flags; | 386 | unsigned long flags; |
| 390 | 387 | ||
| 391 | pci_set_power_state(pci_dev, PCI_D0); | ||
| 392 | pci_restore_state(pci_dev); | ||
| 393 | |||
| 394 | /* Do things that are done in tw68_initdev , | 388 | /* Do things that are done in tw68_initdev , |
| 395 | except of initializing memory structures.*/ | 389 | except of initializing memory structures.*/ |
| 396 | 390 | ||
| @@ -408,19 +402,17 @@ static int tw68_resume(struct pci_dev *pci_dev) · 11 unmodified lines | |||
| 408 | 402 | ||
| 409 | return 0; | 403 | return 0; |
| 410 | } | 404 | } |
| 411 | #endif | ||
| 412 | 405 | ||
| 413 | /* ----------------------------------------------------------- */ | 406 | /* ----------------------------------------------------------- */ |
| 414 | 407 | ||
| 408 | static SIMPLE_DEV_PM_OPS(tw68_pm_ops, tw68_suspend, tw68_resume); | ||
| 409 | |||
| 415 | static struct pci_driver tw68_pci_driver = { | 410 | static struct pci_driver tw68_pci_driver = { |
| 416 | .name = "tw68", | 411 | .name = "tw68", |
| 417 | .id_table = tw68_pci_tbl, | 412 | .id_table = tw68_pci_tbl, |
| 418 | .probe = tw68_initdev, | 413 | .probe = tw68_initdev, |
| 419 | .remove = tw68_finidev, | 414 | .remove = tw68_finidev, |
| 420 | #ifdef CONFIG_PM | 415 | .driver.pm = &tw68_pm_ops, |
| 421 | .suspend = tw68_suspend, | ||
| 422 | .resume = tw68_resume | ||
| 423 | #endif | ||
| 424 | }; | 416 | }; |
| 425 | 417 | ||
| 426 | module_pci_driver(tw68_pci_driver); | 418 | module_pci_driver(tw68_pci_driver); |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | #include <media/v4l2-ctrls.h> | 26 | #include <media/v4l2-ctrls.h> |
| 27 | #include <media/v4l2-event.h> | 27 | #include <media/v4l2-event.h> |
| 28 | #include <media/v4l2-fwnode.h> | 28 | #include <media/v4l2-fwnode.h> |
| 29 | #include <media/v4l2-rect.h> | ||
| 29 | 30 | ||
| 30 | #include "am437x-vpfe.h" | 31 | #include "am437x-vpfe.h" |
| 31 | 32 | ||
| @@ -1987,20 +1988,6 @@ vpfe_g_selection(struct file *file, void *fh, struct v4l2_selection *s) · 1955 unmodified lines | |||
| 1987 | return 0; | 1988 | return 0; |
| 1988 | } | 1989 | } |
| 1989 | 1990 | ||
| 1990 | static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) | ||
| 1991 | { | ||
| 1992 | if (a->left < b->left || a->top < b->top) | ||
| 1993 | return 0; | ||
| 1994 | |||
| 1995 | if (a->left + a->width > b->left + b->width) | ||
| 1996 | return 0; | ||
| 1997 | |||
| 1998 | if (a->top + a->height > b->top + b->height) | ||
| 1999 | return 0; | ||
| 2000 | |||
| 2001 | return 1; | ||
| 2002 | } | ||
| 2003 | |||
| 2004 | static int | 1991 | static int |
| 2005 | vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) | 1992 | vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) |
| 2006 | { | 1993 | { |
| @@ -2025,10 +2012,10 @@ vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) · 18 unmodified lines | |||
| 2025 | r.left = clamp_t(unsigned int, r.left, 0, cr.width - r.width); | 2012 | r.left = clamp_t(unsigned int, r.left, 0, cr.width - r.width); |
| 2026 | r.top = clamp_t(unsigned int, r.top, 0, cr.height - r.height); | 2013 | r.top = clamp_t(unsigned int, r.top, 0, cr.height - r.height); |
| 2027 | 2014 | ||
| 2028 | if (s->flags & V4L2_SEL_FLAG_LE && !enclosed_rectangle(&r, &s->r)) | 2015 | if (s->flags & V4L2_SEL_FLAG_LE && !v4l2_rect_enclosed(&r, &s->r)) |
| 2029 | return -ERANGE; | 2016 | return -ERANGE; |
| 2030 | 2017 | ||
| 2031 | if (s->flags & V4L2_SEL_FLAG_GE && !enclosed_rectangle(&s->r, &r)) | 2018 | if (s->flags & V4L2_SEL_FLAG_GE && !v4l2_rect_enclosed(&s->r, &r)) |
| 2032 | return -ERANGE; | 2019 | return -ERANGE; |
| 2033 | 2020 | ||
| 2034 | s->r = vpfe->crop = r; | 2021 | s->r = vpfe->crop = r; |
| @@ -225,9 +225,6 @@ const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { · 224 unmodified lines | |||
| 225 | (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \ | 225 | (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \ |
| 226 | (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8))) | 226 | (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8))) |
| 227 | 227 | ||
| 228 | #define ISC_CTRL_ISC_TO_V4L2(x) ((x) == ISC_WB_O_ZERO_VAL ? 0 : (x)) | ||
| 229 | #define ISC_CTRL_V4L2_TO_ISC(x) ((x) ? (x) : ISC_WB_O_ZERO_VAL) | ||
| 230 | |||
| 231 | static inline void isc_update_v4l2_ctrls(struct isc_device *isc) | 228 | static inline void isc_update_v4l2_ctrls(struct isc_device *isc) |
| 232 | { | 229 | { |
| 233 | struct isc_ctrls *ctrls = &isc->ctrls; | 230 | struct isc_ctrls *ctrls = &isc->ctrls; |
| @@ -238,14 +235,10 @@ static inline void isc_update_v4l2_ctrls(struct isc_device *isc) · 4 unmodified lines | |||
| 238 | v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]); | 235 | v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]); |
| 239 | v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]); | 236 | v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]); |
| 240 | 237 | ||
| 241 | v4l2_ctrl_s_ctrl(isc->r_off_ctrl, | 238 | v4l2_ctrl_s_ctrl(isc->r_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_R]); |
| 242 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R])); | 239 | v4l2_ctrl_s_ctrl(isc->b_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_B]); |
| 243 | v4l2_ctrl_s_ctrl(isc->b_off_ctrl, | 240 | v4l2_ctrl_s_ctrl(isc->gr_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GR]); |
| 244 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B])); | 241 | v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GB]); |
| 245 | v4l2_ctrl_s_ctrl(isc->gr_off_ctrl, | ||
| 246 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR])); | ||
| 247 | v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, | ||
| 248 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB])); | ||
| 249 | } | 242 | } |
| 250 | 243 | ||
| 251 | static inline void isc_update_awb_ctrls(struct isc_device *isc) | 244 | static inline void isc_update_awb_ctrls(struct isc_device *isc) |
| @@ -255,11 +248,11 @@ static inline void isc_update_awb_ctrls(struct isc_device *isc) · 3 unmodified lines | |||
| 255 | /* In here we set our actual hw pipeline config */ | 248 | /* In here we set our actual hw pipeline config */ |
| 256 | 249 | ||
| 257 | regmap_write(isc->regmap, ISC_WB_O_RGR, | 250 | regmap_write(isc->regmap, ISC_WB_O_RGR, |
| 258 | (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | | 251 | ((ctrls->offset[ISC_HIS_CFG_MODE_R])) | |
| 259 | ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); | 252 | ((ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); |
| 260 | regmap_write(isc->regmap, ISC_WB_O_BGB, | 253 | regmap_write(isc->regmap, ISC_WB_O_BGB, |
| 261 | (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) | | 254 | ((ctrls->offset[ISC_HIS_CFG_MODE_B])) | |
| 262 | ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); | 255 | ((ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); |
| 263 | regmap_write(isc->regmap, ISC_WB_G_RGR, | 256 | regmap_write(isc->regmap, ISC_WB_G_RGR, |
| 264 | ctrls->gain[ISC_HIS_CFG_MODE_R] | | 257 | ctrls->gain[ISC_HIS_CFG_MODE_R] | |
| 265 | (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); | 258 | (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); |
| @@ -275,12 +268,8 @@ static inline void isc_reset_awb_ctrls(struct isc_device *isc) · 9 unmodified lines | |||
| 275 | for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { | 268 | for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { |
| 276 | /* gains have a fixed point at 9 decimals */ | 269 | /* gains have a fixed point at 9 decimals */ |
| 277 | isc->ctrls.gain[c] = 1 << 9; | 270 | isc->ctrls.gain[c] = 1 << 9; |
| 278 | /* offsets are in 2's complements, the value | 271 | /* offsets are in 2's complements */ |
| 279 | * will be substracted from ISC_WB_O_ZERO_VAL to obtain | 272 | isc->ctrls.offset[c] = 0; |
| 280 | * 2's complement of a value between 0 and | ||
| 281 | * ISC_WB_O_ZERO_VAL >> 1 | ||
| 282 | */ | ||
| 283 | isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL; | ||
| 284 | } | 273 | } |
| 285 | } | 274 | } |
| 286 | 275 | ||
| @@ -1774,9 +1763,12 @@ static void isc_wb_update(struct isc_ctrls *ctrls) · 1487 unmodified lines | |||
| 1774 | */ | 1763 | */ |
| 1775 | ctrls->offset[c] = (offset[c] - 1) << 3; | 1764 | ctrls->offset[c] = (offset[c] - 1) << 3; |
| 1776 | 1765 | ||
| 1777 | /* the offset is then taken and converted to 2's complements */ | 1766 | /* |
| 1778 | if (!ctrls->offset[c]) | 1767 | * the offset is then taken and converted to 2's complements, |
| 1779 | ctrls->offset[c] = ISC_WB_O_ZERO_VAL; | 1768 | * and must be negative, as we subtract this value from the |
| 1769 | * color components | ||
| 1770 | */ | ||
| 1771 | ctrls->offset[c] = -ctrls->offset[c]; | ||
| 1780 | 1772 | ||
| 1781 | /* | 1773 | /* |
| 1782 | * the stretch gain is the total number of histogram bins | 1774 | * the stretch gain is the total number of histogram bins |
| @@ -1938,17 +1930,13 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) · 155 unmodified lines | |||
| 1938 | ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val; | 1930 | ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val; |
| 1939 | 1931 | ||
| 1940 | if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new) | 1932 | if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new) |
| 1941 | ctrls->offset[ISC_HIS_CFG_MODE_R] = | 1933 | ctrls->offset[ISC_HIS_CFG_MODE_R] = isc->r_off_ctrl->val; |
| 1942 | ISC_CTRL_V4L2_TO_ISC(isc->r_off_ctrl->val); | ||
| 1943 | if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new) | 1934 | if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new) |
| 1944 | ctrls->offset[ISC_HIS_CFG_MODE_B] = | 1935 | ctrls->offset[ISC_HIS_CFG_MODE_B] = isc->b_off_ctrl->val; |
| 1945 | ISC_CTRL_V4L2_TO_ISC(isc->b_off_ctrl->val); | ||
| 1946 | if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new) | 1936 | if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new) |
| 1947 | ctrls->offset[ISC_HIS_CFG_MODE_GR] = | 1937 | ctrls->offset[ISC_HIS_CFG_MODE_GR] = isc->gr_off_ctrl->val; |
| 1948 | ISC_CTRL_V4L2_TO_ISC(isc->gr_off_ctrl->val); | ||
| 1949 | if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new) | 1938 | if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new) |
| 1950 | ctrls->offset[ISC_HIS_CFG_MODE_GB] = | 1939 | ctrls->offset[ISC_HIS_CFG_MODE_GB] = isc->gb_off_ctrl->val; |
| 1951 | ISC_CTRL_V4L2_TO_ISC(isc->gb_off_ctrl->val); | ||
| 1952 | 1940 | ||
| 1953 | isc_update_awb_ctrls(isc); | 1941 | isc_update_awb_ctrls(isc); |
| 1954 | 1942 | ||
| @@ -2010,13 +1998,13 @@ static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl) · 55 unmodified lines | |||
| 2010 | ctrls->gain[ISC_HIS_CFG_MODE_GB]; | 1998 | ctrls->gain[ISC_HIS_CFG_MODE_GB]; |
| 2011 | 1999 | ||
| 2012 | ctrl->cluster[ISC_CTRL_R_OFF]->val = | 2000 | ctrl->cluster[ISC_CTRL_R_OFF]->val = |
| 2013 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R]); | 2001 | ctrls->offset[ISC_HIS_CFG_MODE_R]; |
| 2014 | ctrl->cluster[ISC_CTRL_B_OFF]->val = | 2002 | ctrl->cluster[ISC_CTRL_B_OFF]->val = |
| 2015 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B]); | 2003 | ctrls->offset[ISC_HIS_CFG_MODE_B]; |
| 2016 | ctrl->cluster[ISC_CTRL_GR_OFF]->val = | 2004 | ctrl->cluster[ISC_CTRL_GR_OFF]->val = |
| 2017 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR]); | 2005 | ctrls->offset[ISC_HIS_CFG_MODE_GR]; |
| 2018 | ctrl->cluster[ISC_CTRL_GB_OFF]->val = | 2006 | ctrl->cluster[ISC_CTRL_GB_OFF]->val = |
| 2019 | ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB]); | 2007 | ctrls->offset[ISC_HIS_CFG_MODE_GB]; |
| 2020 | break; | 2008 | break; |
| 2021 | } | 2009 | } |
| 2022 | return 0; | 2010 | return 0; |
| @@ -108,8 +108,6 @@ · 107 unmodified lines | |||
| 108 | /* ISC White Balance Gain for B, GB Register */ | 108 | /* ISC White Balance Gain for B, GB Register */ |
| 109 | #define ISC_WB_G_BGB 0x0000006c | 109 | #define ISC_WB_G_BGB 0x0000006c |
| 110 | 110 | ||
| 111 | #define ISC_WB_O_ZERO_VAL (1 << 13) | ||
| 112 | |||
| 113 | /* ISC Color Filter Array Control Register */ | 111 | /* ISC Color Filter Array Control Register */ |
| 114 | #define ISC_CFA_CTRL 0x00000070 | 112 | #define ISC_CFA_CTRL 0x00000070 |
| 115 | 113 | ||
| @@ -133,7 +133,7 @@ struct isc_ctrls { · 132 unmodified lines | |||
| 133 | 133 | ||
| 134 | /* one for each component : GR, R, GB, B */ | 134 | /* one for each component : GR, R, GB, B */ |
| 135 | u32 gain[HIST_BAYER]; | 135 | u32 gain[HIST_BAYER]; |
| 136 | u32 offset[HIST_BAYER]; | 136 | s32 offset[HIST_BAYER]; |
| 137 | 137 | ||
| 138 | u32 hist_entry[HIST_ENTRIES]; | 138 | u32 hist_entry[HIST_ENTRIES]; |
| 139 | u32 hist_count[HIST_BAYER]; | 139 | u32 hist_count[HIST_BAYER]; |
| @@ -321,11 +321,13 @@ static const struct dev_pm_ops atmel_isc_dev_pm_ops = { · 320 unmodified lines | |||
| 321 | SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) | 321 | SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) |
| 322 | }; | 322 | }; |
| 323 | 323 | ||
| 324 | #if IS_ENABLED(CONFIG_OF) | ||
| 324 | static const struct of_device_id atmel_isc_of_match[] = { | 325 | static const struct of_device_id atmel_isc_of_match[] = { |
| 325 | { .compatible = "atmel,sama5d2-isc" }, | 326 | { .compatible = "atmel,sama5d2-isc" }, |
| 326 | { } | 327 | { } |
| 327 | }; | 328 | }; |
| 328 | MODULE_DEVICE_TABLE(of, atmel_isc_of_match); | 329 | MODULE_DEVICE_TABLE(of, atmel_isc_of_match); |
| 330 | #endif | ||
| 329 | 331 | ||
| 330 | static struct platform_driver atmel_isc_driver = { | 332 | static struct platform_driver atmel_isc_driver = { |
| 331 | .probe = atmel_isc_probe, | 333 | .probe = atmel_isc_probe, |
| @@ -2653,7 +2653,7 @@ static int coda_open(struct file *file) · 2652 unmodified lines | |||
| 2653 | 2653 | ||
| 2654 | ret = clk_prepare_enable(dev->clk_per); | 2654 | ret = clk_prepare_enable(dev->clk_per); |
| 2655 | if (ret) | 2655 | if (ret) |
| 2656 | goto err_clk_per; | 2656 | goto err_pm_get; |
| 2657 | 2657 | ||
| 2658 | ret = clk_prepare_enable(dev->clk_ahb); | 2658 | ret = clk_prepare_enable(dev->clk_ahb); |
| 2659 | if (ret) | 2659 | if (ret) |
| @@ -2692,9 +2692,8 @@ err_ctx_init: · 32 unmodified lines | |||
| 2692 | clk_disable_unprepare(dev->clk_ahb); | 2692 | clk_disable_unprepare(dev->clk_ahb); |
| 2693 | err_clk_ahb: | 2693 | err_clk_ahb: |
| 2694 | clk_disable_unprepare(dev->clk_per); | 2694 | clk_disable_unprepare(dev->clk_per); |
| 2695 | err_clk_per: | ||
| 2696 | pm_runtime_put_sync(dev->dev); | ||
| 2697 | err_pm_get: | 2695 | err_pm_get: |
| 2696 | pm_runtime_put_sync(dev->dev); | ||
| 2698 | v4l2_fh_del(&ctx->fh); | 2697 | v4l2_fh_del(&ctx->fh); |
| 2699 | v4l2_fh_exit(&ctx->fh); | 2698 | v4l2_fh_exit(&ctx->fh); |
| 2700 | err_coda_name_init: | 2699 | err_coda_name_init: |
| @@ -327,8 +327,11 @@ int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb) · 326 unmodified lines | |||
| 327 | "only 8-bit quantization tables supported\n"); | 327 | "only 8-bit quantization tables supported\n"); |
| 328 | continue; | 328 | continue; |
| 329 | } | 329 | } |
| 330 | if (!ctx->params.jpeg_qmat_tab[i]) | 330 | if (!ctx->params.jpeg_qmat_tab[i]) { |
| 331 | ctx->params.jpeg_qmat_tab[i] = kmalloc(64, GFP_KERNEL); | 331 | ctx->params.jpeg_qmat_tab[i] = kmalloc(64, GFP_KERNEL); |
| 332 | if (!ctx->params.jpeg_qmat_tab[i]) | ||
| 333 | return -ENOMEM; | ||
| 334 | } | ||
| 332 | memcpy(ctx->params.jpeg_qmat_tab[i], | 335 | memcpy(ctx->params.jpeg_qmat_tab[i], |
| 333 | quantization_tables[i].start, 64); | 336 | quantization_tables[i].start, 64); |
| 334 | } | 337 | } |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ | 3 | * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ |
| 4 | */ | 4 | */ |
| 5 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
| 6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | * The hardware supports SDTV, HDTV formats, raw data capture. | 5 | * The hardware supports SDTV, HDTV formats, raw data capture. |
| 6 | * Currently, the driver supports NTSC and PAL standards. | 6 | * Currently, the driver supports NTSC and PAL standards. |
| 7 | * | 7 | * |
| 8 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | 8 | * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or | 10 | * This program is free software; you can redistribute it and/or |
| 11 | * modify it under the terms of the GNU General Public License as | 11 | * modify it under the terms of the GNU General Public License as |
| @@ -458,6 +458,7 @@ static int vpif_probe(struct platform_device *pdev) · 446 unmodified lines | |||
| 458 | res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 458 | res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 459 | if (!res_irq) { | 459 | if (!res_irq) { |
| 460 | dev_warn(&pdev->dev, "Missing IRQ resource.\n"); | 460 | dev_warn(&pdev->dev, "Missing IRQ resource.\n"); |
| 461 | pm_runtime_put(&pdev->dev); | ||
| 461 | return -EINVAL; | 462 | return -EINVAL; |
| 462 | } | 463 | } |
| 463 | 464 | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * VPIF header file | 2 | * VPIF header file |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | 4 | * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
| @@ -1482,8 +1482,6 @@ probe_out: · 1481 unmodified lines | |||
| 1482 | /* Unregister video device */ | 1482 | /* Unregister video device */ |
| 1483 | video_unregister_device(&ch->video_dev); | 1483 | video_unregister_device(&ch->video_dev); |
| 1484 | } | 1484 | } |
| 1485 | kfree(vpif_obj.sd); | ||
| 1486 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
| 1487 | 1485 | ||
| 1488 | return err; | 1486 | return err; |
| 1489 | } | 1487 | } |
| @@ -2,7 +2,7 @@ · 1 unmodified line | |||
| 2 | * vpif-display - VPIF display driver | 2 | * vpif-display - VPIF display driver |
| 3 | * Display driver for TI DaVinci VPIF | 3 | * Display driver for TI DaVinci VPIF |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | 5 | * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ |
| 6 | * Copyright (C) 2014 Lad, Prabhakar <prabhakar.csengg@gmail.com> | 6 | * Copyright (C) 2014 Lad, Prabhakar <prabhakar.csengg@gmail.com> |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * VPIF display header file | 2 | * VPIF display header file |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | 4 | * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
| @@ -505,19 +505,31 @@ static void vpss_exit(void) · 504 unmodified lines | |||
| 505 | 505 | ||
| 506 | static int __init vpss_init(void) | 506 | static int __init vpss_init(void) |
| 507 | { | 507 | { |
| 508 | int ret; | ||
| 509 | |||
| 508 | if (!request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control")) | 510 | if (!request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control")) |
| 509 | return -EBUSY; | 511 | return -EBUSY; |
| 510 | 512 | ||
| 511 | oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4); | 513 | oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4); |
| 512 | if (unlikely(!oper_cfg.vpss_regs_base2)) { | 514 | if (unlikely(!oper_cfg.vpss_regs_base2)) { |
| 513 | release_mem_region(VPSS_CLK_CTRL, 4); | 515 | ret = -ENOMEM; |
| 514 | return -ENOMEM; | 516 | goto err_ioremap; |
| 515 | } | 517 | } |
| 516 | 518 | ||
| 517 | writel(VPSS_CLK_CTRL_VENCCLKEN | | 519 | writel(VPSS_CLK_CTRL_VENCCLKEN | |
| 518 | VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2); | 520 | VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2); |
| 521 | |||
| 522 | ret = platform_driver_register(&vpss_driver); | ||
| 523 | if (ret) | ||
| 524 | goto err_pd_register; | ||
| 525 | |||
| 526 | return 0; | ||
| 519 | 527 | ||
| 520 | return platform_driver_register(&vpss_driver); | 528 | err_pd_register: |
| 529 | iounmap(oper_cfg.vpss_regs_base2); | ||
| 530 | err_ioremap: | ||
| 531 | release_mem_region(VPSS_CLK_CTRL, 4); | ||
| 532 | return ret; | ||
| 521 | } | 533 | } |
| 522 | subsys_initcall(vpss_init); | 534 | subsys_initcall(vpss_init); |
| 523 | module_exit(vpss_exit); | 535 | module_exit(vpss_exit); |
| @@ -577,7 +577,7 @@ int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s) · 576 unmodified lines | |||
| 577 | v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x, | 577 | v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x, |
| 578 | &tmp_h, min_h, max_h, mod_y, 0); | 578 | &tmp_h, min_h, max_h, mod_y, 0); |
| 579 | 579 | ||
| 580 | if (!V4L2_TYPE_IS_OUTPUT(s->type) && | 580 | if (V4L2_TYPE_IS_CAPTURE(s->type) && |
| 581 | (ctx->gsc_ctrls.rotate->val == 90 || | 581 | (ctx->gsc_ctrls.rotate->val == 90 || |
| 582 | ctx->gsc_ctrls.rotate->val == 270)) | 582 | ctx->gsc_ctrls.rotate->val == 270)) |
| 583 | gsc_check_crop_change(tmp_h, tmp_w, | 583 | gsc_check_crop_change(tmp_h, tmp_w, |
| @@ -255,7 +255,7 @@ static int gsc_m2m_buf_prepare(struct vb2_buffer *vb) · 254 unmodified lines | |||
| 255 | if (IS_ERR(frame)) | 255 | if (IS_ERR(frame)) |
| 256 | return PTR_ERR(frame); | 256 | return PTR_ERR(frame); |
| 257 | 257 | ||
| 258 | if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { | 258 | if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { |
| 259 | for (i = 0; i < frame->fmt->num_planes; i++) | 259 | for (i = 0; i < frame->fmt->num_planes; i++) |
| 260 | vb2_set_plane_payload(vb, i, frame->payload[i]); | 260 | vb2_set_plane_payload(vb, i, frame->payload[i]); |
| 261 | } | 261 | } |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include <media/v4l2-device.h> | 21 | #include <media/v4l2-device.h> |
| 22 | #include <media/v4l2-ioctl.h> | 22 | #include <media/v4l2-ioctl.h> |
| 23 | #include <media/v4l2-mem2mem.h> | 23 | #include <media/v4l2-mem2mem.h> |
| 24 | #include <media/v4l2-rect.h> | ||
| 24 | #include <media/videobuf2-v4l2.h> | 25 | #include <media/videobuf2-v4l2.h> |
| 25 | #include <media/videobuf2-dma-contig.h> | 26 | #include <media/videobuf2-dma-contig.h> |
| 26 | 27 | ||
| @@ -478,8 +479,10 @@ static int fimc_capture_open(struct file *file) · 451 unmodified lines | |||
| 478 | 479 | ||
| 479 | set_bit(ST_CAPT_BUSY, &fimc->state); | 480 | set_bit(ST_CAPT_BUSY, &fimc->state); |
| 480 | ret = pm_runtime_get_sync(&fimc->pdev->dev); | 481 | ret = pm_runtime_get_sync(&fimc->pdev->dev); |
| 481 | if (ret < 0) | 482 | if (ret < 0) { |
| 483 | pm_runtime_put_sync(&fimc->pdev->dev); | ||
| 482 | goto unlock; | 484 | goto unlock; |
| 485 | } | ||
| 483 | 486 | ||
| 484 | ret = v4l2_fh_open(file); | 487 | ret = v4l2_fh_open(file); |
| 485 | if (ret) { | 488 | if (ret) { |
| @@ -1299,19 +1302,6 @@ static int fimc_cap_g_selection(struct file *file, void *fh, · 813 unmodified lines | |||
| 1299 | return -EINVAL; | 1302 | return -EINVAL; |
| 1300 | } | 1303 | } |
| 1301 | 1304 | ||
| 1302 | /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ | ||
| 1303 | static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) | ||
| 1304 | { | ||
| 1305 | if (a->left < b->left || a->top < b->top) | ||
| 1306 | return 0; | ||
| 1307 | if (a->left + a->width > b->left + b->width) | ||
| 1308 | return 0; | ||
| 1309 | if (a->top + a->height > b->top + b->height) | ||
| 1310 | return 0; | ||
| 1311 | |||
| 1312 | return 1; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | static int fimc_cap_s_selection(struct file *file, void *fh, | 1305 | static int fimc_cap_s_selection(struct file *file, void *fh, |
| 1316 | struct v4l2_selection *s) | 1306 | struct v4l2_selection *s) |
| 1317 | { | 1307 | { |
| @@ -1334,11 +1324,11 @@ static int fimc_cap_s_selection(struct file *file, void *fh, · 16 unmodified lines | |||
| 1334 | fimc_capture_try_selection(ctx, &rect, s->target); | 1324 | fimc_capture_try_selection(ctx, &rect, s->target); |
| 1335 | 1325 | ||
| 1336 | if (s->flags & V4L2_SEL_FLAG_LE && | 1326 | if (s->flags & V4L2_SEL_FLAG_LE && |
| 1337 | !enclosed_rectangle(&rect, &s->r)) | 1327 | !v4l2_rect_enclosed(&rect, &s->r)) |
| 1338 | return -ERANGE; | 1328 | return -ERANGE; |
| 1339 | 1329 | ||
| 1340 | if (s->flags & V4L2_SEL_FLAG_GE && | 1330 | if (s->flags & V4L2_SEL_FLAG_GE && |
| 1341 | !enclosed_rectangle(&s->r, &rect)) | 1331 | !v4l2_rect_enclosed(&s->r, &rect)) |
| 1342 | return -ERANGE; | 1332 | return -ERANGE; |
| 1343 | 1333 | ||
| 1344 | s->r = rect; | 1334 | s->r = rect; |
| @@ -871,6 +871,7 @@ err_dfs: · 870 unmodified lines | |||
| 871 | err_sd: | 871 | err_sd: |
| 872 | fimc_is_unregister_subdevs(is); | 872 | fimc_is_unregister_subdevs(is); |
| 873 | err_pm: | 873 | err_pm: |
| 874 | pm_runtime_put_noidle(dev); | ||
| 874 | if (!pm_runtime_enabled(dev)) | 875 | if (!pm_runtime_enabled(dev)) |
| 875 | fimc_is_runtime_suspend(dev); | 876 | fimc_is_runtime_suspend(dev); |
| 876 | err_irq: | 877 | err_irq: |
| @@ -293,6 +293,7 @@ static int isp_video_open(struct file *file) · 292 unmodified lines | |||
| 293 | if (!ret) | 293 | if (!ret) |
| 294 | goto unlock; | 294 | goto unlock; |
| 295 | rel_fh: | 295 | rel_fh: |
| 296 | pm_runtime_put_noidle(&isp->pdev->dev); | ||
| 296 | v4l2_fh_release(file); | 297 | v4l2_fh_release(file); |
| 297 | unlock: | 298 | unlock: |
| 298 | mutex_unlock(&isp->video_lock); | 299 | mutex_unlock(&isp->video_lock); |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <media/v4l2-device.h> | 25 | #include <media/v4l2-device.h> |
| 26 | #include <media/v4l2-ioctl.h> | 26 | #include <media/v4l2-ioctl.h> |
| 27 | #include <media/v4l2-mem2mem.h> | 27 | #include <media/v4l2-mem2mem.h> |
| 28 | #include <media/v4l2-rect.h> | ||
| 28 | #include <media/videobuf2-v4l2.h> | 29 | #include <media/videobuf2-v4l2.h> |
| 29 | #include <media/videobuf2-dma-contig.h> | 30 | #include <media/videobuf2-dma-contig.h> |
| 30 | #include <media/drv-intf/exynos-fimc.h> | 31 | #include <media/drv-intf/exynos-fimc.h> |
| @@ -868,19 +869,6 @@ static int fimc_lite_reqbufs(struct file *file, void *priv, · 837 unmodified lines | |||
| 868 | return ret; | 869 | return ret; |
| 869 | } | 870 | } |
| 870 | 871 | ||
| 871 | /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ | ||
| 872 | static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) | ||
| 873 | { | ||
| 874 | if (a->left < b->left || a->top < b->top) | ||
| 875 | return 0; | ||
| 876 | if (a->left + a->width > b->left + b->width) | ||
| 877 | return 0; | ||
| 878 | if (a->top + a->height > b->top + b->height) | ||
| 879 | return 0; | ||
| 880 | |||
| 881 | return 1; | ||
| 882 | } | ||
| 883 | |||
| 884 | static int fimc_lite_g_selection(struct file *file, void *fh, | 872 | static int fimc_lite_g_selection(struct file *file, void *fh, |
| 885 | struct v4l2_selection *sel) | 873 | struct v4l2_selection *sel) |
| 886 | { | 874 | { |
| @@ -922,11 +910,11 @@ static int fimc_lite_s_selection(struct file *file, void *fh, · 35 unmodified lines | |||
| 922 | fimc_lite_try_compose(fimc, &rect); | 910 | fimc_lite_try_compose(fimc, &rect); |
| 923 | 911 | ||
| 924 | if ((sel->flags & V4L2_SEL_FLAG_LE) && | 912 | if ((sel->flags & V4L2_SEL_FLAG_LE) && |
| 925 | !enclosed_rectangle(&rect, &sel->r)) | 913 | !v4l2_rect_enclosed(&rect, &sel->r)) |
| 926 | return -ERANGE; | 914 | return -ERANGE; |
| 927 | 915 | ||
| 928 | if ((sel->flags & V4L2_SEL_FLAG_GE) && | 916 | if ((sel->flags & V4L2_SEL_FLAG_GE) && |
| 929 | !enclosed_rectangle(&sel->r, &rect)) | 917 | !v4l2_rect_enclosed(&sel->r, &rect)) |
| 930 | return -ERANGE; | 918 | return -ERANGE; |
| 931 | 919 | ||
| 932 | sel->r = rect; | 920 | sel->r = rect; |
| @@ -1270,6 +1270,9 @@ static int fimc_md_get_pinctrl(struct fimc_md *fmd) · 1269 unmodified lines | |||
| 1270 | 1270 | ||
| 1271 | pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl, | 1271 | pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl, |
| 1272 | PINCTRL_STATE_IDLE); | 1272 | PINCTRL_STATE_IDLE); |
| 1273 | if (IS_ERR(pctl->state_idle)) | ||
| 1274 | return PTR_ERR(pctl->state_idle); | ||
| 1275 | |||
| 1273 | return 0; | 1276 | return 0; |
| 1274 | } | 1277 | } |
| 1275 | 1278 | ||
| @@ -1439,7 +1442,7 @@ static int fimc_md_probe(struct platform_device *pdev) · 163 unmodified lines | |||
| 1439 | INIT_LIST_HEAD(&fmd->pipelines); | 1442 | INIT_LIST_HEAD(&fmd->pipelines); |
| 1440 | fmd->pdev = pdev; | 1443 | fmd->pdev = pdev; |
| 1441 | 1444 | ||
| 1442 | strscpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", | 1445 | strscpy(fmd->media_dev.model, "Samsung S5P FIMC", |
| 1443 | sizeof(fmd->media_dev.model)); | 1446 | sizeof(fmd->media_dev.model)); |
| 1444 | fmd->media_dev.ops = &fimc_md_ops; | 1447 | fmd->media_dev.ops = &fimc_md_ops; |
| 1445 | fmd->media_dev.dev = dev; | 1448 | fmd->media_dev.dev = dev; |
| @@ -604,44 +604,28 @@ static void cafe_pci_remove(struct pci_dev *pdev) · 603 unmodified lines | |||
| 604 | } | 604 | } |
| 605 | 605 | ||
| 606 | 606 | ||
| 607 | #ifdef CONFIG_PM | ||
| 608 | /* | 607 | /* |
| 609 | * Basic power management. | 608 | * Basic power management. |
| 610 | */ | 609 | */ |
| 611 | static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 610 | static int __maybe_unused cafe_pci_suspend(struct device *dev) |
| 612 | { | 611 | { |
| 613 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); | 612 | struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); |
| 614 | struct cafe_camera *cam = to_cam(v4l2_dev); | 613 | struct cafe_camera *cam = to_cam(v4l2_dev); |
| 615 | int ret; | ||
| 616 | 614 | ||
| 617 | ret = pci_save_state(pdev); | ||
| 618 | if (ret) | ||
| 619 | return ret; | ||
| 620 | mccic_suspend(&cam->mcam); | 615 | mccic_suspend(&cam->mcam); |
| 621 | pci_disable_device(pdev); | ||
| 622 | return 0; | 616 | return 0; |
| 623 | } | 617 | } |
| 624 | 618 | ||
| 625 | 619 | ||
| 626 | static int cafe_pci_resume(struct pci_dev *pdev) | 620 | static int __maybe_unused cafe_pci_resume(struct device *dev) |
| 627 | { | 621 | { |
| 628 | struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); | 622 | struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); |
| 629 | struct cafe_camera *cam = to_cam(v4l2_dev); | 623 | struct cafe_camera *cam = to_cam(v4l2_dev); |
| 630 | int ret = 0; | ||
| 631 | 624 | ||
| 632 | pci_restore_state(pdev); | ||
| 633 | ret = pci_enable_device(pdev); | ||
| 634 | |||
| 635 | if (ret) { | ||
| 636 | cam_warn(cam, "Unable to re-enable device on resume!\n"); | ||
| 637 | return ret; | ||
| 638 | } | ||
| 639 | cafe_ctlr_init(&cam->mcam); | 625 | cafe_ctlr_init(&cam->mcam); |
| 640 | return mccic_resume(&cam->mcam); | 626 | return mccic_resume(&cam->mcam); |
| 641 | } | 627 | } |
| 642 | 628 | ||
| 643 | #endif /* CONFIG_PM */ | ||
| 644 | |||
| 645 | static const struct pci_device_id cafe_ids[] = { | 629 | static const struct pci_device_id cafe_ids[] = { |
| 646 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, | 630 | { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, |
| 647 | PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, | 631 | PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, |
| @@ -650,15 +634,14 @@ static const struct pci_device_id cafe_ids[] = { · 2 unmodified lines | |||
| 650 | 634 | ||
| 651 | MODULE_DEVICE_TABLE(pci, cafe_ids); | 635 | MODULE_DEVICE_TABLE(pci, cafe_ids); |
| 652 | 636 | ||
| 637 | static SIMPLE_DEV_PM_OPS(cafe_pci_pm_ops, cafe_pci_suspend, cafe_pci_resume); | ||
| 638 | |||
| 653 | static struct pci_driver cafe_pci_driver = { | 639 | static struct pci_driver cafe_pci_driver = { |
| 654 | .name = "cafe1000-ccic", | 640 | .name = "cafe1000-ccic", |
| 655 | .id_table = cafe_ids, | 641 | .id_table = cafe_ids, |
| 656 | .probe = cafe_pci_probe, | 642 | .probe = cafe_pci_probe, |
| 657 | .remove = cafe_pci_remove, | 643 | .remove = cafe_pci_remove, |
| 658 | #ifdef CONFIG_PM | 644 | .driver.pm = &cafe_pci_pm_ops, |
| 659 | .suspend = cafe_pci_suspend, | ||
| 660 | .resume = cafe_pci_resume, | ||
| 661 | #endif | ||
| 662 | }; | 645 | }; |
| 663 | 646 | ||
| 664 | 647 | ||
| @@ -1940,6 +1940,7 @@ int mccic_register(struct mcam_camera *cam) · 1939 unmodified lines | |||
| 1940 | out: | 1940 | out: |
| 1941 | v4l2_async_notifier_unregister(&cam->notifier); | 1941 | v4l2_async_notifier_unregister(&cam->notifier); |
| 1942 | v4l2_device_unregister(&cam->v4l2_dev); | 1942 | v4l2_device_unregister(&cam->v4l2_dev); |
| 1943 | v4l2_async_notifier_cleanup(&cam->notifier); | ||
| 1943 | return ret; | 1944 | return ret; |
| 1944 | } | 1945 | } |
| 1945 | EXPORT_SYMBOL_GPL(mccic_register); | 1946 | EXPORT_SYMBOL_GPL(mccic_register); |
| @@ -1961,14 +1962,13 @@ void mccic_shutdown(struct mcam_camera *cam) · 15 unmodified lines | |||
| 1961 | v4l2_ctrl_handler_free(&cam->ctrl_handler); | 1962 | v4l2_ctrl_handler_free(&cam->ctrl_handler); |
| 1962 | v4l2_async_notifier_unregister(&cam->notifier); | 1963 | v4l2_async_notifier_unregister(&cam->notifier); |
| 1963 | v4l2_device_unregister(&cam->v4l2_dev); | 1964 | v4l2_device_unregister(&cam->v4l2_dev); |
| 1965 | v4l2_async_notifier_cleanup(&cam->notifier); | ||
| 1964 | } | 1966 | } |
| 1965 | EXPORT_SYMBOL_GPL(mccic_shutdown); | 1967 | EXPORT_SYMBOL_GPL(mccic_shutdown); |
| 1966 | 1968 | ||
| 1967 | /* | 1969 | /* |
| 1968 | * Power management | 1970 | * Power management |
| 1969 | */ | 1971 | */ |
| 1970 | #ifdef CONFIG_PM | ||
| 1971 | |||
| 1972 | void mccic_suspend(struct mcam_camera *cam) | 1972 | void mccic_suspend(struct mcam_camera *cam) |
| 1973 | { | 1973 | { |
| 1974 | mutex_lock(&cam->s_mutex); | 1974 | mutex_lock(&cam->s_mutex); |
| @@ -2015,7 +2015,6 @@ int mccic_resume(struct mcam_camera *cam) · 40 unmodified lines | |||
| 2015 | return ret; | 2015 | return ret; |
| 2016 | } | 2016 | } |
| 2017 | EXPORT_SYMBOL_GPL(mccic_resume); | 2017 | EXPORT_SYMBOL_GPL(mccic_resume); |
| 2018 | #endif /* CONFIG_PM */ | ||
| 2019 | 2018 | ||
| 2020 | MODULE_LICENSE("GPL v2"); | 2019 | MODULE_LICENSE("GPL v2"); |
| 2021 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | 2020 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
| @@ -236,10 +236,8 @@ static inline void mcam_reg_set_bit(struct mcam_camera *cam, · 235 unmodified lines | |||
| 236 | int mccic_register(struct mcam_camera *cam); | 236 | int mccic_register(struct mcam_camera *cam); |
| 237 | int mccic_irq(struct mcam_camera *cam, unsigned int irqs); | 237 | int mccic_irq(struct mcam_camera *cam, unsigned int irqs); |
| 238 | void mccic_shutdown(struct mcam_camera *cam); | 238 | void mccic_shutdown(struct mcam_camera *cam); |
| 239 | #ifdef CONFIG_PM | ||
| 240 | void mccic_suspend(struct mcam_camera *cam); | 239 | void mccic_suspend(struct mcam_camera *cam); |
| 241 | int mccic_resume(struct mcam_camera *cam); | 240 | int mccic_resume(struct mcam_camera *cam); |
| 242 | #endif | ||
| 243 | 241 | ||
| 244 | /* | 242 | /* |
| 245 | * Register definitions for the m88alp01 camera interface. Offsets in bytes | 243 | * Register definitions for the m88alp01 camera interface. Offsets in bytes |
| @@ -731,7 +731,7 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q) · 730 unmodified lines | |||
| 731 | * subsampling. Update capture queue when the stream is off. | 731 | * subsampling. Update capture queue when the stream is off. |
| 732 | */ | 732 | */ |
| 733 | if (ctx->state == MTK_JPEG_SOURCE_CHANGE && | 733 | if (ctx->state == MTK_JPEG_SOURCE_CHANGE && |
| 734 | !V4L2_TYPE_IS_OUTPUT(q->type)) { | 734 | V4L2_TYPE_IS_CAPTURE(q->type)) { |
| 735 | struct mtk_jpeg_src_buf *src_buf; | 735 | struct mtk_jpeg_src_buf *src_buf; |
| 736 | 736 | ||
| 737 | vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | 737 | vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
| @@ -14,46 +14,6 @@ · 13 unmodified lines | |||
| 14 | #include "mtk_mdp_comp.h" | 14 | #include "mtk_mdp_comp.h" |
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | static const char * const mtk_mdp_comp_stem[MTK_MDP_COMP_TYPE_MAX] = { | ||
| 18 | "mdp-rdma", | ||
| 19 | "mdp-rsz", | ||
| 20 | "mdp-wdma", | ||
| 21 | "mdp-wrot", | ||
| 22 | }; | ||
| 23 | |||
| 24 | struct mtk_mdp_comp_match { | ||
| 25 | enum mtk_mdp_comp_type type; | ||
| 26 | int alias_id; | ||
| 27 | }; | ||
| 28 | |||
| 29 | static const struct mtk_mdp_comp_match mtk_mdp_matches[MTK_MDP_COMP_ID_MAX] = { | ||
| 30 | { MTK_MDP_RDMA, 0 }, | ||
| 31 | { MTK_MDP_RDMA, 1 }, | ||
| 32 | { MTK_MDP_RSZ, 0 }, | ||
| 33 | { MTK_MDP_RSZ, 1 }, | ||
| 34 | { MTK_MDP_RSZ, 2 }, | ||
| 35 | { MTK_MDP_WDMA, 0 }, | ||
| 36 | { MTK_MDP_WROT, 0 }, | ||
| 37 | { MTK_MDP_WROT, 1 }, | ||
| 38 | }; | ||
| 39 | |||
| 40 | int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node, | ||
| 41 | enum mtk_mdp_comp_type comp_type) | ||
| 42 | { | ||
| 43 | int id = of_alias_get_id(node, mtk_mdp_comp_stem[comp_type]); | ||
| 44 | int i; | ||
| 45 | |||
| 46 | for (i = 0; i < ARRAY_SIZE(mtk_mdp_matches); i++) { | ||
| 47 | if (comp_type == mtk_mdp_matches[i].type && | ||
| 48 | id == mtk_mdp_matches[i].alias_id) | ||
| 49 | return i; | ||
| 50 | } | ||
| 51 | |||
| 52 | dev_err(dev, "Failed to get id. type: %d, id: %d\n", comp_type, id); | ||
| 53 | |||
| 54 | return -EINVAL; | ||
| 55 | } | ||
| 56 | |||
| 57 | void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) | 17 | void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) |
| 58 | { | 18 | { |
| 59 | int i, err; | 19 | int i, err; |
| @@ -62,8 +22,8 @@ void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) · 2 unmodified lines | |||
| 62 | err = mtk_smi_larb_get(comp->larb_dev); | 22 | err = mtk_smi_larb_get(comp->larb_dev); |
| 63 | if (err) | 23 | if (err) |
| 64 | dev_err(dev, | 24 | dev_err(dev, |
| 65 | "failed to get larb, err %d. type:%d id:%d\n", | 25 | "failed to get larb, err %d. type:%d\n", |
| 66 | err, comp->type, comp->id); | 26 | err, comp->type); |
| 67 | } | 27 | } |
| 68 | 28 | ||
| 69 | for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { | 29 | for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { |
| @@ -72,8 +32,8 @@ void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) · 2 unmodified lines | |||
| 72 | err = clk_prepare_enable(comp->clk[i]); | 32 | err = clk_prepare_enable(comp->clk[i]); |
| 73 | if (err) | 33 | if (err) |
| 74 | dev_err(dev, | 34 | dev_err(dev, |
| 75 | "failed to enable clock, err %d. type:%d id:%d i:%d\n", | 35 | "failed to enable clock, err %d. type:%d i:%d\n", |
| 76 | err, comp->type, comp->id, i); | 36 | err, comp->type, i); |
| 77 | } | 37 | } |
| 78 | } | 38 | } |
| 79 | 39 | ||
| @@ -92,29 +52,24 @@ void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp) · 12 unmodified lines | |||
| 92 | } | 52 | } |
| 93 | 53 | ||
| 94 | int mtk_mdp_comp_init(struct device *dev, struct device_node *node, | 54 | int mtk_mdp_comp_init(struct device *dev, struct device_node *node, |
| 95 | struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id) | 55 | struct mtk_mdp_comp *comp, |
| 56 | enum mtk_mdp_comp_type comp_type) | ||
| 96 | { | 57 | { |
| 97 | struct device_node *larb_node; | 58 | struct device_node *larb_node; |
| 98 | struct platform_device *larb_pdev; | 59 | struct platform_device *larb_pdev; |
| 60 | int ret; | ||
| 99 | int i; | 61 | int i; |
| 100 | 62 | ||
| 101 | if (comp_id < 0 || comp_id >= MTK_MDP_COMP_ID_MAX) { | ||
| 102 | dev_err(dev, "Invalid comp_id %d\n", comp_id); | ||
| 103 | return -EINVAL; | ||
| 104 | } | ||
| 105 | |||
| 106 | comp->dev_node = of_node_get(node); | 63 | comp->dev_node = of_node_get(node); |
| 107 | comp->id = comp_id; | 64 | comp->type = comp_type; |
| 108 | comp->type = mtk_mdp_matches[comp_id].type; | ||
| 109 | comp->regs = of_iomap(node, 0); | ||
| 110 | 65 | ||
| 111 | for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { | 66 | for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { |
| 112 | comp->clk[i] = of_clk_get(node, i); | 67 | comp->clk[i] = of_clk_get(node, i); |
| 113 | if (IS_ERR(comp->clk[i])) { | 68 | if (IS_ERR(comp->clk[i])) { |
| 114 | if (PTR_ERR(comp->clk[i]) != -EPROBE_DEFER) | 69 | if (PTR_ERR(comp->clk[i]) != -EPROBE_DEFER) |
| 115 | dev_err(dev, "Failed to get clock\n"); | 70 | dev_err(dev, "Failed to get clock\n"); |
| 116 | 71 | ret = PTR_ERR(comp->clk[i]); | |
| 117 | return PTR_ERR(comp->clk[i]); | 72 | goto put_dev; |
| 118 | } | 73 | } |
| 119 | 74 | ||
| 120 | /* Only RDMA needs two clocks */ | 75 | /* Only RDMA needs two clocks */ |
| @@ -133,20 +88,27 @@ int mtk_mdp_comp_init(struct device *dev, struct device_node *node, · 12 unmodified lines | |||
| 133 | if (!larb_node) { | 88 | if (!larb_node) { |
| 134 | dev_err(dev, | 89 | dev_err(dev, |
| 135 | "Missing mediadek,larb phandle in %pOF node\n", node); | 90 | "Missing mediadek,larb phandle in %pOF node\n", node); |
| 136 | return -EINVAL; | 91 | ret = -EINVAL; |
| 92 | goto put_dev; | ||
| 137 | } | 93 | } |
| 138 | 94 | ||
| 139 | larb_pdev = of_find_device_by_node(larb_node); | 95 | larb_pdev = of_find_device_by_node(larb_node); |
| 140 | if (!larb_pdev) { | 96 | if (!larb_pdev) { |
| 141 | dev_warn(dev, "Waiting for larb device %pOF\n", larb_node); | 97 | dev_warn(dev, "Waiting for larb device %pOF\n", larb_node); |
| 142 | of_node_put(larb_node); | 98 | of_node_put(larb_node); |
| 143 | return -EPROBE_DEFER; | 99 | ret = -EPROBE_DEFER; |
| 100 | goto put_dev; | ||
| 144 | } | 101 | } |
| 145 | of_node_put(larb_node); | 102 | of_node_put(larb_node); |
| 146 | 103 | ||
| 147 | comp->larb_dev = &larb_pdev->dev; | 104 | comp->larb_dev = &larb_pdev->dev; |
| 148 | 105 | ||
| 149 | return 0; | 106 | return 0; |
| 107 | |||
| 108 | put_dev: | ||
| 109 | of_node_put(comp->dev_node); | ||
| 110 | |||
| 111 | return ret; | ||
| 150 | } | 112 | } |
| 151 | 113 | ||
| 152 | void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp) | 114 | void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp) |
| @@ -22,41 +22,26 @@ enum mtk_mdp_comp_type { · 21 unmodified lines | |||
| 22 | MTK_MDP_COMP_TYPE_MAX, | 22 | MTK_MDP_COMP_TYPE_MAX, |
| 23 | }; | 23 | }; |
| 24 | 24 | ||
| 25 | enum mtk_mdp_comp_id { | ||
| 26 | MTK_MDP_COMP_RDMA0, | ||
| 27 | MTK_MDP_COMP_RDMA1, | ||
| 28 | MTK_MDP_COMP_RSZ0, | ||
| 29 | MTK_MDP_COMP_RSZ1, | ||
| 30 | MTK_MDP_COMP_RSZ2, | ||
| 31 | MTK_MDP_COMP_WDMA, | ||
| 32 | MTK_MDP_COMP_WROT0, | ||
| 33 | MTK_MDP_COMP_WROT1, | ||
| 34 | MTK_MDP_COMP_ID_MAX, | ||
| 35 | }; | ||
| 36 | |||
| 37 | /** | 25 | /** |
| 38 | * struct mtk_mdp_comp - the MDP's function component data | 26 | * struct mtk_mdp_comp - the MDP's function component data |
| 27 | * @node: list node to track sibing MDP components | ||
| 39 | * @dev_node: component device node | 28 | * @dev_node: component device node |
| 40 | * @clk: clocks required for component | 29 | * @clk: clocks required for component |
| 41 | * @regs: Mapped address of component registers. | ||
| 42 | * @larb_dev: SMI device required for component | 30 | * @larb_dev: SMI device required for component |
| 43 | * @type: component type | 31 | * @type: component type |
| 44 | * @id: component ID | ||
| 45 | */ | 32 | */ |
| 46 | struct mtk_mdp_comp { | 33 | struct mtk_mdp_comp { |
| 34 | struct list_head node; | ||
| 47 | struct device_node *dev_node; | 35 | struct device_node *dev_node; |
| 48 | struct clk *clk[2]; | 36 | struct clk *clk[2]; |
| 49 | void __iomem *regs; | ||
| 50 | struct device *larb_dev; | 37 | struct device *larb_dev; |
| 51 | enum mtk_mdp_comp_type type; | 38 | enum mtk_mdp_comp_type type; |
| 52 | enum mtk_mdp_comp_id id; | ||
| 53 | }; | 39 | }; |
| 54 | 40 | ||
| 55 | int mtk_mdp_comp_init(struct device *dev, struct device_node *node, | 41 | int mtk_mdp_comp_init(struct device *dev, struct device_node *node, |
| 56 | struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id); | 42 | struct mtk_mdp_comp *comp, |
| 43 | enum mtk_mdp_comp_type comp_type); | ||
| 57 | void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp); | 44 | void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp); |
| 58 | int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node, | ||
| 59 | enum mtk_mdp_comp_type comp_type); | ||
| 60 | void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp); | 45 | void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp); |
| 61 | void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp); | 46 | void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp); |
| 62 | 47 | ||
| @@ -55,19 +55,19 @@ MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids); · 54 unmodified lines | |||
| 55 | static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp) | 55 | static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp) |
| 56 | { | 56 | { |
| 57 | struct device *dev = &mdp->pdev->dev; | 57 | struct device *dev = &mdp->pdev->dev; |
| 58 | int i; | 58 | struct mtk_mdp_comp *comp_node; |
| 59 | 59 | ||
| 60 | for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) | 60 | list_for_each_entry(comp_node, &mdp->comp_list, node) |
| 61 | mtk_mdp_comp_clock_on(dev, mdp->comp[i]); | 61 | mtk_mdp_comp_clock_on(dev, comp_node); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp) | 64 | static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp) |
| 65 | { | 65 | { |
| 66 | struct device *dev = &mdp->pdev->dev; | 66 | struct device *dev = &mdp->pdev->dev; |
| 67 | int i; | 67 | struct mtk_mdp_comp *comp_node; |
| 68 | 68 | ||
| 69 | for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) | 69 | list_for_each_entry(comp_node, &mdp->comp_list, node) |
| 70 | mtk_mdp_comp_clock_off(dev, mdp->comp[i]); | 70 | mtk_mdp_comp_clock_off(dev, comp_node); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static void mtk_mdp_wdt_worker(struct work_struct *work) | 73 | static void mtk_mdp_wdt_worker(struct work_struct *work) |
| @@ -91,12 +91,25 @@ static void mtk_mdp_reset_handler(void *priv) · 17 unmodified lines | |||
| 91 | queue_work(mdp->wdt_wq, &mdp->wdt_work); | 91 | queue_work(mdp->wdt_wq, &mdp->wdt_work); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | void mtk_mdp_register_component(struct mtk_mdp_dev *mdp, | ||
| 95 | struct mtk_mdp_comp *comp) | ||
| 96 | { | ||
| 97 | list_add(&mdp->comp_list, &comp->node); | ||
| 98 | } | ||
| 99 | |||
| 100 | void mtk_mdp_unregister_component(struct mtk_mdp_dev *mdp, | ||
| 101 | struct mtk_mdp_comp *comp) | ||
| 102 | { | ||
| 103 | list_del(&comp->node); | ||
| 104 | } | ||
| 105 | |||
| 94 | static int mtk_mdp_probe(struct platform_device *pdev) | 106 | static int mtk_mdp_probe(struct platform_device *pdev) |
| 95 | { | 107 | { |
| 96 | struct mtk_mdp_dev *mdp; | 108 | struct mtk_mdp_dev *mdp; |
| 97 | struct device *dev = &pdev->dev; | 109 | struct device *dev = &pdev->dev; |
| 98 | struct device_node *node, *parent; | 110 | struct device_node *node, *parent; |
| 99 | int i, ret = 0; | 111 | struct mtk_mdp_comp *comp, *comp_temp; |
| 112 | int ret = 0; | ||
| 100 | 113 | ||
| 101 | mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL); | 114 | mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL); |
| 102 | if (!mdp) | 115 | if (!mdp) |
| @@ -104,6 +117,7 @@ static int mtk_mdp_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 104 | 117 | ||
| 105 | mdp->id = pdev->id; | 118 | mdp->id = pdev->id; |
| 106 | mdp->pdev = pdev; | 119 | mdp->pdev = pdev; |
| 120 | INIT_LIST_HEAD(&mdp->comp_list); | ||
| 107 | INIT_LIST_HEAD(&mdp->ctx_list); | 121 | INIT_LIST_HEAD(&mdp->ctx_list); |
| 108 | 122 | ||
| 109 | mutex_init(&mdp->lock); | 123 | mutex_init(&mdp->lock); |
| @@ -123,8 +137,6 @@ static int mtk_mdp_probe(struct platform_device *pdev) · 13 unmodified lines | |||
| 123 | for_each_child_of_node(parent, node) { | 137 | for_each_child_of_node(parent, node) { |
| 124 | const struct of_device_id *of_id; | 138 | const struct of_device_id *of_id; |
| 125 | enum mtk_mdp_comp_type comp_type; | 139 | enum mtk_mdp_comp_type comp_type; |
| 126 | int comp_id; | ||
| 127 | struct mtk_mdp_comp *comp; | ||
| 128 | 140 | ||
| 129 | of_id = of_match_node(mtk_mdp_comp_dt_ids, node); | 141 | of_id = of_match_node(mtk_mdp_comp_dt_ids, node); |
| 130 | if (!of_id) | 142 | if (!of_id) |
| @@ -137,12 +149,6 @@ static int mtk_mdp_probe(struct platform_device *pdev) · 6 unmodified lines | |||
| 137 | } | 149 | } |
| 138 | 150 | ||
| 139 | comp_type = (enum mtk_mdp_comp_type)of_id->data; | 151 | comp_type = (enum mtk_mdp_comp_type)of_id->data; |
| 140 | comp_id = mtk_mdp_comp_get_id(dev, node, comp_type); | ||
| 141 | if (comp_id < 0) { | ||
| 142 | dev_warn(dev, "Skipping unknown component %pOF\n", | ||
| 143 | node); | ||
| 144 | continue; | ||
| 145 | } | ||
| 146 | 152 | ||
| 147 | comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); | 153 | comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); |
| 148 | if (!comp) { | 154 | if (!comp) { |
| @@ -150,13 +156,14 @@ static int mtk_mdp_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 150 | of_node_put(node); | 156 | of_node_put(node); |
| 151 | goto err_comp; | 157 | goto err_comp; |
| 152 | } | 158 | } |
| 153 | mdp->comp[comp_id] = comp; | ||
| 154 | 159 | ||
| 155 | ret = mtk_mdp_comp_init(dev, node, comp, comp_id); | 160 | ret = mtk_mdp_comp_init(dev, node, comp, comp_type); |
| 156 | if (ret) { | 161 | if (ret) { |
| 157 | of_node_put(node); | 162 | of_node_put(node); |
| 158 | goto err_comp; | 163 | goto err_comp; |
| 159 | } | 164 | } |
| 165 | |||
| 166 | mtk_mdp_register_component(mdp, comp); | ||
| 160 | } | 167 | } |
| 161 | 168 | ||
| 162 | mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME); | 169 | mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME); |
| @@ -188,12 +195,20 @@ static int mtk_mdp_probe(struct platform_device *pdev) · 25 unmodified lines | |||
| 188 | } | 195 | } |
| 189 | 196 | ||
| 190 | mdp->vpu_dev = vpu_get_plat_device(pdev); | 197 | mdp->vpu_dev = vpu_get_plat_device(pdev); |
| 191 | vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp, | 198 | ret = vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp, |
| 192 | VPU_RST_MDP); | 199 | VPU_RST_MDP); |
| 200 | if (ret) { | ||
| 201 | dev_err(&pdev->dev, "Failed to register reset handler\n"); | ||
| 202 | goto err_m2m_register; | ||
| 203 | } | ||
| 193 | 204 | ||
| 194 | platform_set_drvdata(pdev, mdp); | 205 | platform_set_drvdata(pdev, mdp); |
| 195 | 206 | ||
| 196 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); | 207 | ret = vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); |
| 208 | if (ret) { | ||
| 209 | dev_err(&pdev->dev, "Failed to set vb2 dma mag seg size\n"); | ||
| 210 | goto err_m2m_register; | ||
| 211 | } | ||
| 197 | 212 | ||
| 198 | pm_runtime_enable(dev); | 213 | pm_runtime_enable(dev); |
| 199 | dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id); | 214 | dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id); |
| @@ -212,8 +227,10 @@ err_alloc_wdt_wq: · 12 unmodified lines | |||
| 212 | err_alloc_job_wq: | 227 | err_alloc_job_wq: |
| 213 | 228 | ||
| 214 | err_comp: | 229 | err_comp: |
| 215 | for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) | 230 | list_for_each_entry_safe(comp, comp_temp, &mdp->comp_list, node) { |
| 216 | mtk_mdp_comp_deinit(dev, mdp->comp[i]); | 231 | mtk_mdp_unregister_component(mdp, comp); |
| 232 | mtk_mdp_comp_deinit(dev, comp); | ||
| 233 | } | ||
| 217 | 234 | ||
| 218 | dev_dbg(dev, "err %d\n", ret); | 235 | dev_dbg(dev, "err %d\n", ret); |
| 219 | return ret; | 236 | return ret; |
| @@ -222,7 +239,7 @@ err_comp: · 2 unmodified lines | |||
| 222 | static int mtk_mdp_remove(struct platform_device *pdev) | 239 | static int mtk_mdp_remove(struct platform_device *pdev) |
| 223 | { | 240 | { |
| 224 | struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev); | 241 | struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev); |
| 225 | int i; | 242 | struct mtk_mdp_comp *comp, *comp_temp; |
| 226 | 243 | ||
| 227 | pm_runtime_disable(&pdev->dev); | 244 | pm_runtime_disable(&pdev->dev); |
| 228 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); | 245 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); |
| @@ -235,8 +252,10 @@ static int mtk_mdp_remove(struct platform_device *pdev) · 6 unmodified lines | |||
| 235 | flush_workqueue(mdp->job_wq); | 252 | flush_workqueue(mdp->job_wq); |
| 236 | destroy_workqueue(mdp->job_wq); | 253 | destroy_workqueue(mdp->job_wq); |
| 237 | 254 | ||
| 238 | for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) | 255 | list_for_each_entry_safe(comp, comp_temp, &mdp->comp_list, node) { |
| 239 | mtk_mdp_comp_deinit(&pdev->dev, mdp->comp[i]); | 256 | mtk_mdp_unregister_component(mdp, comp); |
| 257 | mtk_mdp_comp_deinit(&pdev->dev, comp); | ||
| 258 | } | ||
| 240 | 259 | ||
| 241 | dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); | 260 | dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); |
| 242 | return 0; | 261 | return 0; |
| @@ -28,8 +28,6 @@ · 27 unmodified lines | |||
| 28 | #define MTK_MDP_FMT_FLAG_CAPTURE BIT(1) | 28 | #define MTK_MDP_FMT_FLAG_CAPTURE BIT(1) |
| 29 | 29 | ||
| 30 | #define MTK_MDP_VPU_INIT BIT(0) | 30 | #define MTK_MDP_VPU_INIT BIT(0) |
| 31 | #define MTK_MDP_SRC_FMT BIT(1) | ||
| 32 | #define MTK_MDP_DST_FMT BIT(2) | ||
| 33 | #define MTK_MDP_CTX_ERROR BIT(5) | 31 | #define MTK_MDP_CTX_ERROR BIT(5) |
| 34 | 32 | ||
| 35 | /** | 33 | /** |
| @@ -138,7 +136,7 @@ struct mtk_mdp_variant { · 102 unmodified lines | |||
| 138 | * @pdev: pointer to the image processor platform device | 136 | * @pdev: pointer to the image processor platform device |
| 139 | * @variant: the IP variant information | 137 | * @variant: the IP variant information |
| 140 | * @id: image processor device index (0..MTK_MDP_MAX_DEVS) | 138 | * @id: image processor device index (0..MTK_MDP_MAX_DEVS) |
| 141 | * @comp: MDP function components | 139 | * @comp_list: list of MDP function components |
| 142 | * @m2m_dev: v4l2 memory-to-memory device data | 140 | * @m2m_dev: v4l2 memory-to-memory device data |
| 143 | * @ctx_list: list of struct mtk_mdp_ctx | 141 | * @ctx_list: list of struct mtk_mdp_ctx |
| 144 | * @vdev: video device for image processor driver | 142 | * @vdev: video device for image processor driver |
| @@ -156,7 +154,7 @@ struct mtk_mdp_dev { · 11 unmodified lines | |||
| 156 | struct platform_device *pdev; | 154 | struct platform_device *pdev; |
| 157 | struct mtk_mdp_variant *variant; | 155 | struct mtk_mdp_variant *variant; |
| 158 | u16 id; | 156 | u16 id; |
| 159 | struct mtk_mdp_comp *comp[MTK_MDP_COMP_ID_MAX]; | 157 | struct list_head comp_list; |
| 160 | struct v4l2_m2m_dev *m2m_dev; | 158 | struct v4l2_m2m_dev *m2m_dev; |
| 161 | struct list_head ctx_list; | 159 | struct list_head ctx_list; |
| 162 | struct video_device *vdev; | 160 | struct video_device *vdev; |
| @@ -223,6 +221,12 @@ struct mtk_mdp_ctx { · 60 unmodified lines | |||
| 223 | 221 | ||
| 224 | extern int mtk_mdp_dbg_level; | 222 | extern int mtk_mdp_dbg_level; |
| 225 | 223 | ||
| 224 | void mtk_mdp_register_component(struct mtk_mdp_dev *mdp, | ||
| 225 | struct mtk_mdp_comp *comp); | ||
| 226 | |||
| 227 | void mtk_mdp_unregister_component(struct mtk_mdp_dev *mdp, | ||
| 228 | struct mtk_mdp_comp *comp); | ||
| 229 | |||
| 226 | #if defined(DEBUG) | 230 | #if defined(DEBUG) |
| 227 | 231 | ||
| 228 | #define mtk_mdp_dbg(level, fmt, args...) \ | 232 | #define mtk_mdp_dbg(level, fmt, args...) \ |
| @@ -193,7 +193,7 @@ static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx, · 192 unmodified lines | |||
| 193 | 193 | ||
| 194 | pix_mp->field = V4L2_FIELD_NONE; | 194 | pix_mp->field = V4L2_FIELD_NONE; |
| 195 | pix_mp->pixelformat = fmt->pixelformat; | 195 | pix_mp->pixelformat = fmt->pixelformat; |
| 196 | if (!V4L2_TYPE_IS_OUTPUT(f->type)) { | 196 | if (V4L2_TYPE_IS_CAPTURE(f->type)) { |
| 197 | pix_mp->colorspace = ctx->colorspace; | 197 | pix_mp->colorspace = ctx->colorspace; |
| 198 | pix_mp->xfer_func = ctx->xfer_func; | 198 | pix_mp->xfer_func = ctx->xfer_func; |
| 199 | pix_mp->ycbcr_enc = ctx->ycbcr_enc; | 199 | pix_mp->ycbcr_enc = ctx->ycbcr_enc; |
| @@ -327,9 +327,8 @@ static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type, · 127 unmodified lines | |||
| 327 | mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w, | 327 | mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w, |
| 328 | &new_h, min_h, max_h, align_h); | 328 | &new_h, min_h, max_h, align_h); |
| 329 | 329 | ||
| 330 | if (!V4L2_TYPE_IS_OUTPUT(type) && | 330 | if (V4L2_TYPE_IS_CAPTURE(type) && |
| 331 | (ctx->ctrls.rotate->val == 90 || | 331 | (ctx->ctrls.rotate->val == 90 || ctx->ctrls.rotate->val == 270)) |
| 332 | ctx->ctrls.rotate->val == 270)) | ||
| 333 | mtk_mdp_check_crop_change(new_h, new_w, | 332 | mtk_mdp_check_crop_change(new_h, new_w, |
| 334 | &r->width, &r->height); | 333 | &r->width, &r->height); |
| 335 | else | 334 | else |
| @@ -369,13 +368,6 @@ void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state) · 33 unmodified lines | |||
| 369 | mutex_unlock(&ctx->slock); | 368 | mutex_unlock(&ctx->slock); |
| 370 | } | 369 | } |
| 371 | 370 | ||
| 372 | static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx *ctx, u32 state) | ||
| 373 | { | ||
| 374 | mutex_lock(&ctx->slock); | ||
| 375 | ctx->state &= ~state; | ||
| 376 | mutex_unlock(&ctx->slock); | ||
| 377 | } | ||
| 378 | |||
| 379 | static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask) | 371 | static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask) |
| 380 | { | 372 | { |
| 381 | bool ret; | 373 | bool ret; |
| @@ -726,11 +718,6 @@ static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh, · 344 unmodified lines | |||
| 726 | ctx->quant = pix_mp->quantization; | 718 | ctx->quant = pix_mp->quantization; |
| 727 | } | 719 | } |
| 728 | 720 | ||
| 729 | if (V4L2_TYPE_IS_OUTPUT(f->type)) | ||
| 730 | mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_SRC_FMT); | ||
| 731 | else | ||
| 732 | mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_DST_FMT); | ||
| 733 | |||
| 734 | mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type, | 721 | mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type, |
| 735 | frame->width, frame->height); | 722 | frame->width, frame->height); |
| 736 | 723 | ||
| @@ -742,13 +729,6 @@ static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh, · 5 unmodified lines | |||
| 742 | { | 729 | { |
| 743 | struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); | 730 | struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); |
| 744 | 731 | ||
| 745 | if (reqbufs->count == 0) { | ||
| 746 | if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
| 747 | mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_SRC_FMT); | ||
| 748 | else | ||
| 749 | mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_DST_FMT); | ||
| 750 | } | ||
| 751 | |||
| 752 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | 732 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); |
| 753 | } | 733 | } |
| 754 | 734 | ||
| @@ -758,14 +738,6 @@ static int mtk_mdp_m2m_streamon(struct file *file, void *fh, · 3 unmodified lines | |||
| 758 | struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); | 738 | struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); |
| 759 | int ret; | 739 | int ret; |
| 760 | 740 | ||
| 761 | /* The source and target color format need to be set */ | ||
| 762 | if (V4L2_TYPE_IS_OUTPUT(type)) { | ||
| 763 | if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_SRC_FMT)) | ||
| 764 | return -EINVAL; | ||
| 765 | } else if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT)) { | ||
| 766 | return -EINVAL; | ||
| 767 | } | ||
| 768 | |||
| 769 | if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) { | 741 | if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) { |
| 770 | ret = mtk_mdp_vpu_init(&ctx->vpu); | 742 | ret = mtk_mdp_vpu_init(&ctx->vpu); |
| 771 | if (ret < 0) { | 743 | if (ret < 0) { |
| @@ -899,24 +871,21 @@ static int mtk_mdp_m2m_s_selection(struct file *file, void *fh, · 127 unmodified lines | |||
| 899 | frame = &ctx->d_frame; | 871 | frame = &ctx->d_frame; |
| 900 | 872 | ||
| 901 | /* Check to see if scaling ratio is within supported range */ | 873 | /* Check to see if scaling ratio is within supported range */ |
| 902 | if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT)) { | 874 | if (V4L2_TYPE_IS_OUTPUT(s->type)) |
| 903 | if (V4L2_TYPE_IS_OUTPUT(s->type)) { | 875 | ret = mtk_mdp_check_scaler_ratio(variant, new_r.width, |
| 904 | ret = mtk_mdp_check_scaler_ratio(variant, new_r.width, | 876 | new_r.height, ctx->d_frame.crop.width, |
| 905 | new_r.height, ctx->d_frame.crop.width, | 877 | ctx->d_frame.crop.height, |
| 906 | ctx->d_frame.crop.height, | 878 | ctx->ctrls.rotate->val); |
| 907 | ctx->ctrls.rotate->val); | 879 | else |
| 908 | } else { | 880 | ret = mtk_mdp_check_scaler_ratio(variant, |
| 909 | ret = mtk_mdp_check_scaler_ratio(variant, | 881 | ctx->s_frame.crop.width, |
| 910 | ctx->s_frame.crop.width, | 882 | ctx->s_frame.crop.height, new_r.width, |
| 911 | ctx->s_frame.crop.height, new_r.width, | 883 | new_r.height, ctx->ctrls.rotate->val); |
| 912 | new_r.height, ctx->ctrls.rotate->val); | ||
| 913 | } | ||
| 914 | 884 | ||
| 915 | if (ret) { | 885 | if (ret) { |
| 916 | dev_info(&ctx->mdp_dev->pdev->dev, | 886 | dev_info(&ctx->mdp_dev->pdev->dev, |
| 917 | "Out of scaler range"); | 887 | "Out of scaler range"); |
| 918 | return -EINVAL; | 888 | return -EINVAL; |
| 919 | } | ||
| 920 | } | 889 | } |
| 921 | 890 | ||
| 922 | s->r = new_r; | 891 | s->r = new_r; |
| @@ -989,7 +958,6 @@ static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl) · 66 unmodified lines | |||
| 989 | struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl); | 958 | struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl); |
| 990 | struct mtk_mdp_dev *mdp = ctx->mdp_dev; | 959 | struct mtk_mdp_dev *mdp = ctx->mdp_dev; |
| 991 | struct mtk_mdp_variant *variant = mdp->variant; | 960 | struct mtk_mdp_variant *variant = mdp->variant; |
| 992 | u32 state = MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT; | ||
| 993 | int ret = 0; | 961 | int ret = 0; |
| 994 | 962 | ||
| 995 | if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) | 963 | if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) |
| @@ -1003,17 +971,15 @@ static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl) · 7 unmodified lines | |||
| 1003 | ctx->vflip = ctrl->val; | 971 | ctx->vflip = ctrl->val; |
| 1004 | break; | 972 | break; |
| 1005 | case V4L2_CID_ROTATE: | 973 | case V4L2_CID_ROTATE: |
| 1006 | if (mtk_mdp_ctx_state_is_set(ctx, state)) { | 974 | ret = mtk_mdp_check_scaler_ratio(variant, |
| 1007 | ret = mtk_mdp_check_scaler_ratio(variant, | 975 | ctx->s_frame.crop.width, |
| 1008 | ctx->s_frame.crop.width, | 976 | ctx->s_frame.crop.height, |
| 1009 | ctx->s_frame.crop.height, | 977 | ctx->d_frame.crop.width, |
| 1010 | ctx->d_frame.crop.width, | 978 | ctx->d_frame.crop.height, |
| 1011 | ctx->d_frame.crop.height, | 979 | ctx->ctrls.rotate->val); |
| 1012 | ctx->ctrls.rotate->val); | 980 | |
| 1013 | 981 | if (ret) | |
| 1014 | if (ret) | 982 | return -EINVAL; |
| 1015 | return -EINVAL; | ||
| 1016 | } | ||
| 1017 | 983 | ||
| 1018 | ctx->rotation = ctrl->val; | 984 | ctx->rotation = ctrl->val; |
| 1019 | break; | 985 | break; |
| @@ -1090,6 +1056,7 @@ static int mtk_mdp_m2m_open(struct file *file) · 70 unmodified lines | |||
| 1090 | struct video_device *vfd = video_devdata(file); | 1056 | struct video_device *vfd = video_devdata(file); |
| 1091 | struct mtk_mdp_ctx *ctx = NULL; | 1057 | struct mtk_mdp_ctx *ctx = NULL; |
| 1092 | int ret; | 1058 | int ret; |
| 1059 | struct v4l2_format default_format; | ||
| 1093 | 1060 | ||
| 1094 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 1061 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
| 1095 | if (!ctx) | 1062 | if (!ctx) |
| @@ -1144,6 +1111,16 @@ static int mtk_mdp_m2m_open(struct file *file) · 48 unmodified lines | |||
| 1144 | list_add(&ctx->list, &mdp->ctx_list); | 1111 | list_add(&ctx->list, &mdp->ctx_list); |
| 1145 | mutex_unlock(&mdp->lock); | 1112 | mutex_unlock(&mdp->lock); |
| 1146 | 1113 | ||
| 1114 | /* Default format */ | ||
| 1115 | memset(&default_format, 0, sizeof(default_format)); | ||
| 1116 | default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | ||
| 1117 | default_format.fmt.pix_mp.width = 32; | ||
| 1118 | default_format.fmt.pix_mp.height = 32; | ||
| 1119 | default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M; | ||
| 1120 | mtk_mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format); | ||
| 1121 | default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | ||
| 1122 | mtk_mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format); | ||
| 1123 | |||
| 1147 | mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id); | 1124 | mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id); |
| 1148 | 1125 | ||
| 1149 | return 0; | 1126 | return 0; |
| @@ -2287,7 +2287,7 @@ static int preview_init_entities(struct isp_prev_device *prev) · 2286 unmodified lines | |||
| 2287 | me->ops = &preview_media_ops; | 2287 | me->ops = &preview_media_ops; |
| 2288 | ret = media_entity_pads_init(me, PREV_PADS_NUM, pads); | 2288 | ret = media_entity_pads_init(me, PREV_PADS_NUM, pads); |
| 2289 | if (ret < 0) | 2289 | if (ret < 0) |
| 2290 | return ret; | 2290 | goto error_handler_free; |
| 2291 | 2291 | ||
| 2292 | preview_init_formats(sd, NULL); | 2292 | preview_init_formats(sd, NULL); |
| 2293 | 2293 | ||
| @@ -2320,6 +2320,8 @@ error_video_out: · 26 unmodified lines | |||
| 2320 | omap3isp_video_cleanup(&prev->video_in); | 2320 | omap3isp_video_cleanup(&prev->video_in); |
| 2321 | error_video_in: | 2321 | error_video_in: |
| 2322 | media_entity_cleanup(&prev->subdev.entity); | 2322 | media_entity_cleanup(&prev->subdev.entity); |
| 2323 | error_handler_free: | ||
| 2324 | v4l2_ctrl_handler_free(&prev->ctrls); | ||
| 2323 | return ret; | 2325 | return ret; |
| 2324 | } | 2326 | } |
| 2325 | 2327 | ||
| @@ -2504,17 +2504,14 @@ static int pxa_camera_probe(struct platform_device *pdev) · 2503 unmodified lines | |||
| 2504 | if (err) | 2504 | if (err) |
| 2505 | goto exit_notifier_cleanup; | 2505 | goto exit_notifier_cleanup; |
| 2506 | 2506 | ||
| 2507 | if (pcdev->mclk) { | 2507 | v4l2_clk_name_i2c(clk_name, sizeof(clk_name), |
| 2508 | v4l2_clk_name_i2c(clk_name, sizeof(clk_name), | 2508 | pcdev->asd.match.i2c.adapter_id, |
| 2509 | pcdev->asd.match.i2c.adapter_id, | 2509 | pcdev->asd.match.i2c.address); |
| 2510 | pcdev->asd.match.i2c.address); | 2510 | |
| 2511 | 2511 | pcdev->mclk_clk = v4l2_clk_register(&pxa_camera_mclk_ops, clk_name, NULL); | |
| 2512 | pcdev->mclk_clk = v4l2_clk_register(&pxa_camera_mclk_ops, | 2512 | if (IS_ERR(pcdev->mclk_clk)) { |
| 2513 | clk_name, NULL); | 2513 | err = PTR_ERR(pcdev->mclk_clk); |
| 2514 | if (IS_ERR(pcdev->mclk_clk)) { | 2514 | goto exit_notifier_cleanup; |
| 2515 | err = PTR_ERR(pcdev->mclk_clk); | ||
| 2516 | goto exit_notifier_cleanup; | ||
| 2517 | } | ||
| 2518 | } | 2515 | } |
| 2519 | 2516 | ||
| 2520 | err = v4l2_async_notifier_register(&pcdev->v4l2_dev, &pcdev->notifier); | 2517 | err = v4l2_async_notifier_register(&pcdev->v4l2_dev, &pcdev->notifier); |
| @@ -2588,7 +2585,7 @@ static struct platform_driver pxa_camera_driver = { · 67 unmodified lines | |||
| 2588 | 2585 | ||
| 2589 | module_platform_driver(pxa_camera_driver); | 2586 | module_platform_driver(pxa_camera_driver); |
| 2590 | 2587 | ||
| 2591 | MODULE_DESCRIPTION("PXA27x SoC Camera Host driver"); | 2588 | MODULE_DESCRIPTION("PXA27x Camera Driver"); |
| 2592 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); | 2589 | MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); |
| 2593 | MODULE_LICENSE("GPL"); | 2590 | MODULE_LICENSE("GPL"); |
| 2594 | MODULE_VERSION(PXA_CAM_VERSION); | 2591 | MODULE_VERSION(PXA_CAM_VERSION); |
| @@ -562,8 +562,10 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) · 561 unmodified lines | |||
| 562 | u32 hw_version; | 562 | u32 hw_version; |
| 563 | 563 | ||
| 564 | ret = pm_runtime_get_sync(dev); | 564 | ret = pm_runtime_get_sync(dev); |
| 565 | if (ret < 0) | 565 | if (ret < 0) { |
| 566 | pm_runtime_put_sync(dev); | ||
| 566 | return ret; | 567 | return ret; |
| 568 | } | ||
| 567 | 569 | ||
| 568 | ret = regulator_enable(csid->vdda); | 570 | ret = regulator_enable(csid->vdda); |
| 569 | if (ret < 0) { | 571 | if (ret < 0) { |
| @@ -1356,7 +1358,7 @@ int msm_csid_register_entity(struct csid_device *csid, · 786 unmodified lines | |||
| 1356 | pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 1358 | pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK; |
| 1357 | pads[MSM_CSID_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; | 1359 | pads[MSM_CSID_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; |
| 1358 | 1360 | ||
| 1359 | sd->entity.function = MEDIA_ENT_F_IO_V4L; | 1361 | sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; |
| 1360 | sd->entity.ops = &csid_media_ops; | 1362 | sd->entity.ops = &csid_media_ops; |
| 1361 | ret = media_entity_pads_init(&sd->entity, MSM_CSID_PADS_NUM, pads); | 1363 | ret = media_entity_pads_init(&sd->entity, MSM_CSID_PADS_NUM, pads); |
| 1362 | if (ret < 0) { | 1364 | if (ret < 0) { |
| @@ -737,7 +737,7 @@ int msm_csiphy_register_entity(struct csiphy_device *csiphy, · 736 unmodified lines | |||
| 737 | pads[MSM_CSIPHY_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 737 | pads[MSM_CSIPHY_PAD_SINK].flags = MEDIA_PAD_FL_SINK; |
| 738 | pads[MSM_CSIPHY_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; | 738 | pads[MSM_CSIPHY_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; |
| 739 | 739 | ||
| 740 | sd->entity.function = MEDIA_ENT_F_IO_V4L; | 740 | sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; |
| 741 | sd->entity.ops = &csiphy_media_ops; | 741 | sd->entity.ops = &csiphy_media_ops; |
| 742 | ret = media_entity_pads_init(&sd->entity, MSM_CSIPHY_PADS_NUM, pads); | 742 | ret = media_entity_pads_init(&sd->entity, MSM_CSIPHY_PADS_NUM, pads); |
| 743 | if (ret < 0) { | 743 | if (ret < 0) { |
| @@ -344,8 +344,10 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on) · 343 unmodified lines | |||
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | ret = pm_runtime_get_sync(dev); | 346 | ret = pm_runtime_get_sync(dev); |
| 347 | if (ret < 0) | 347 | if (ret < 0) { |
| 348 | pm_runtime_put_sync(dev); | ||
| 348 | goto exit; | 349 | goto exit; |
| 350 | } | ||
| 349 | 351 | ||
| 350 | ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev); | 352 | ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev); |
| 351 | if (ret < 0) { | 353 | if (ret < 0) { |
| @@ -1323,7 +1325,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif, · 971 unmodified lines | |||
| 1323 | pads[MSM_ISPIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | 1325 | pads[MSM_ISPIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; |
| 1324 | pads[MSM_ISPIF_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; | 1326 | pads[MSM_ISPIF_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; |
| 1325 | 1327 | ||
| 1326 | sd->entity.function = MEDIA_ENT_F_IO_V4L; | 1328 | sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; |
| 1327 | sd->entity.ops = &ispif_media_ops; | 1329 | sd->entity.ops = &ispif_media_ops; |
| 1328 | ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM, | 1330 | ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM, |
| 1329 | pads); | 1331 | pads); |
| @@ -1265,12 +1265,12 @@ static int vfe_get(struct vfe_device *vfe) · 1264 unmodified lines | |||
| 1265 | 1265 | ||
| 1266 | ret = vfe_set_clock_rates(vfe); | 1266 | ret = vfe_set_clock_rates(vfe); |
| 1267 | if (ret < 0) | 1267 | if (ret < 0) |
| 1268 | goto error_clocks; | 1268 | goto error_pm_runtime_get; |
| 1269 | 1269 | ||
| 1270 | ret = camss_enable_clocks(vfe->nclocks, vfe->clock, | 1270 | ret = camss_enable_clocks(vfe->nclocks, vfe->clock, |
| 1271 | vfe->camss->dev); | 1271 | vfe->camss->dev); |
| 1272 | if (ret < 0) | 1272 | if (ret < 0) |
| 1273 | goto error_clocks; | 1273 | goto error_pm_runtime_get; |
| 1274 | 1274 | ||
| 1275 | ret = vfe_reset(vfe); | 1275 | ret = vfe_reset(vfe); |
| 1276 | if (ret < 0) | 1276 | if (ret < 0) |
| @@ -1282,7 +1282,7 @@ static int vfe_get(struct vfe_device *vfe) · 5 unmodified lines | |||
| 1282 | } else { | 1282 | } else { |
| 1283 | ret = vfe_check_clock_rates(vfe); | 1283 | ret = vfe_check_clock_rates(vfe); |
| 1284 | if (ret < 0) | 1284 | if (ret < 0) |
| 1285 | goto error_clocks; | 1285 | goto error_pm_runtime_get; |
| 1286 | } | 1286 | } |
| 1287 | vfe->power_count++; | 1287 | vfe->power_count++; |
| 1288 | 1288 | ||
| @@ -1293,10 +1293,8 @@ static int vfe_get(struct vfe_device *vfe) · 4 unmodified lines | |||
| 1293 | error_reset: | 1293 | error_reset: |
| 1294 | camss_disable_clocks(vfe->nclocks, vfe->clock); | 1294 | camss_disable_clocks(vfe->nclocks, vfe->clock); |
| 1295 | 1295 | ||
| 1296 | error_clocks: | ||
| 1297 | pm_runtime_put_sync(vfe->camss->dev); | ||
| 1298 | |||
| 1299 | error_pm_runtime_get: | 1296 | error_pm_runtime_get: |
| 1297 | pm_runtime_put_sync(vfe->camss->dev); | ||
| 1300 | camss_pm_domain_off(vfe->camss, vfe->id); | 1298 | camss_pm_domain_off(vfe->camss, vfe->id); |
| 1301 | 1299 | ||
| 1302 | error_pm_domain: | 1300 | error_pm_domain: |
| @@ -504,7 +504,6 @@ static int camss_of_parse_ports(struct camss *camss) · 503 unmodified lines | |||
| 504 | return num_subdevs; | 504 | return num_subdevs; |
| 505 | 505 | ||
| 506 | err_cleanup: | 506 | err_cleanup: |
| 507 | v4l2_async_notifier_cleanup(&camss->notifier); | ||
| 508 | of_node_put(node); | 507 | of_node_put(node); |
| 509 | return ret; | 508 | return ret; |
| 510 | } | 509 | } |
| @@ -835,29 +834,38 @@ static int camss_probe(struct platform_device *pdev) · 324 unmodified lines | |||
| 835 | camss->csid_num = 4; | 834 | camss->csid_num = 4; |
| 836 | camss->vfe_num = 2; | 835 | camss->vfe_num = 2; |
| 837 | } else { | 836 | } else { |
| 838 | return -EINVAL; | 837 | ret = -EINVAL; |
| 838 | goto err_free; | ||
| 839 | } | 839 | } |
| 840 | 840 | ||
| 841 | camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, | 841 | camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, |
| 842 | sizeof(*camss->csiphy), GFP_KERNEL); | 842 | sizeof(*camss->csiphy), GFP_KERNEL); |
| 843 | if (!camss->csiphy) | 843 | if (!camss->csiphy) { |
| 844 | return -ENOMEM; | 844 | ret = -ENOMEM; |
| 845 | goto err_free; | ||
| 846 | } | ||
| 845 | 847 | ||
| 846 | camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), | 848 | camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), |
| 847 | GFP_KERNEL); | 849 | GFP_KERNEL); |
| 848 | if (!camss->csid) | 850 | if (!camss->csid) { |
| 849 | return -ENOMEM; | 851 | ret = -ENOMEM; |
| 852 | goto err_free; | ||
| 853 | } | ||
| 850 | 854 | ||
| 851 | camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe), | 855 | camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe), |
| 852 | GFP_KERNEL); | 856 | GFP_KERNEL); |
| 853 | if (!camss->vfe) | 857 | if (!camss->vfe) { |
| 854 | return -ENOMEM; | 858 | ret = -ENOMEM; |
| 859 | goto err_free; | ||
| 860 | } | ||
| 855 | 861 | ||
| 856 | v4l2_async_notifier_init(&camss->notifier); | 862 | v4l2_async_notifier_init(&camss->notifier); |
| 857 | 863 | ||
| 858 | num_subdevs = camss_of_parse_ports(camss); | 864 | num_subdevs = camss_of_parse_ports(camss); |
| 859 | if (num_subdevs < 0) | 865 | if (num_subdevs < 0) { |
| 860 | return num_subdevs; | 866 | ret = num_subdevs; |
| 867 | goto err_cleanup; | ||
| 868 | } | ||
| 861 | 869 | ||
| 862 | ret = camss_init_subdevices(camss); | 870 | ret = camss_init_subdevices(camss); |
| 863 | if (ret < 0) | 871 | if (ret < 0) |
| @@ -936,6 +944,8 @@ err_register_entities: · 72 unmodified lines | |||
| 936 | v4l2_device_unregister(&camss->v4l2_dev); | 944 | v4l2_device_unregister(&camss->v4l2_dev); |
| 937 | err_cleanup: | 945 | err_cleanup: |
| 938 | v4l2_async_notifier_cleanup(&camss->notifier); | 946 | v4l2_async_notifier_cleanup(&camss->notifier); |
| 947 | err_free: | ||
| 948 | kfree(camss); | ||
| 939 | 949 | ||
| 940 | return ret; | 950 | return ret; |
| 941 | } | 951 | } |
| @@ -496,6 +496,10 @@ min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load) · 495 unmodified lines | |||
| 496 | list_for_each_entry(inst_pos, &core->instances, list) { | 496 | list_for_each_entry(inst_pos, &core->instances, list) { |
| 497 | if (inst_pos == inst) | 497 | if (inst_pos == inst) |
| 498 | continue; | 498 | continue; |
| 499 | |||
| 500 | if (inst_pos->state != INST_START) | ||
| 501 | continue; | ||
| 502 | |||
| 499 | vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq; | 503 | vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq; |
| 500 | coreid = inst_pos->clk_data.core_id; | 504 | coreid = inst_pos->clk_data.core_id; |
| 501 | 505 | ||
| @@ -1177,7 +1177,7 @@ static int venc_open(struct file *file) · 1176 unmodified lines | |||
| 1177 | 1177 | ||
| 1178 | ret = pm_runtime_get_sync(core->dev_enc); | 1178 | ret = pm_runtime_get_sync(core->dev_enc); |
| 1179 | if (ret < 0) | 1179 | if (ret < 0) |
| 1180 | goto err_free_inst; | 1180 | goto err_put_sync; |
| 1181 | 1181 | ||
| 1182 | ret = venc_ctrl_init(inst); | 1182 | ret = venc_ctrl_init(inst); |
| 1183 | if (ret) | 1183 | if (ret) |
| @@ -1222,7 +1222,6 @@ err_ctrl_deinit: · 38 unmodified lines | |||
| 1222 | venc_ctrl_deinit(inst); | 1222 | venc_ctrl_deinit(inst); |
| 1223 | err_put_sync: | 1223 | err_put_sync: |
| 1224 | pm_runtime_put_sync(core->dev_enc); | 1224 | pm_runtime_put_sync(core->dev_enc); |
| 1225 | err_free_inst: | ||
| 1226 | kfree(inst); | 1225 | kfree(inst); |
| 1227 | return ret; | 1226 | return ret; |
| 1228 | } | 1227 | } |
| @@ -320,6 +320,7 @@ static const struct rcar_csi2_format rcar_csi2_formats[] = { · 319 unmodified lines | |||
| 320 | { .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 }, | 320 | { .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 }, |
| 321 | { .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 }, | 321 | { .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 }, |
| 322 | { .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 }, | 322 | { .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 }, |
| 323 | { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .datatype = 0x2a, .bpp = 8 }, | ||
| 323 | }; | 324 | }; |
| 324 | 325 | ||
| 325 | static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) | 326 | static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) |
| @@ -344,7 +345,7 @@ enum rcar_csi2_pads { · 18 unmodified lines | |||
| 344 | 345 | ||
| 345 | struct rcar_csi2_info { | 346 | struct rcar_csi2_info { |
| 346 | int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); | 347 | int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); |
| 347 | int (*confirm_start)(struct rcar_csi2 *priv); | 348 | int (*phy_post_init)(struct rcar_csi2 *priv); |
| 348 | const struct rcsi2_mbps_reg *hsfreqrange; | 349 | const struct rcsi2_mbps_reg *hsfreqrange; |
| 349 | unsigned int csi0clkfreqrange; | 350 | unsigned int csi0clkfreqrange; |
| 350 | unsigned int num_channels; | 351 | unsigned int num_channels; |
| @@ -575,9 +576,9 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) · 224 unmodified lines | |||
| 575 | if (ret) | 576 | if (ret) |
| 576 | return ret; | 577 | return ret; |
| 577 | 578 | ||
| 578 | /* Confirm start */ | 579 | /* Run post PHY start initialization, if needed. */ |
| 579 | if (priv->info->confirm_start) { | 580 | if (priv->info->phy_post_init) { |
| 580 | ret = priv->info->confirm_start(priv); | 581 | ret = priv->info->phy_post_init(priv); |
| 581 | if (ret) | 582 | if (ret) |
| 582 | return ret; | 583 | return ret; |
| 583 | } | 584 | } |
| @@ -975,7 +976,7 @@ static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) · 391 unmodified lines | |||
| 975 | return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); | 976 | return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); |
| 976 | } | 977 | } |
| 977 | 978 | ||
| 978 | static int rcsi2_confirm_start_v3m_e3(struct rcar_csi2 *priv) | 979 | static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) |
| 979 | { | 980 | { |
| 980 | static const struct phtw_value step1[] = { | 981 | static const struct phtw_value step1[] = { |
| 981 | { .data = 0xee, .code = 0x34 }, | 982 | { .data = 0xee, .code = 0x34 }, |
| @@ -1059,7 +1060,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { · 77 unmodified lines | |||
| 1059 | 1060 | ||
| 1060 | static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { | 1061 | static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { |
| 1061 | .init_phtw = rcsi2_init_phtw_v3m_e3, | 1062 | .init_phtw = rcsi2_init_phtw_v3m_e3, |
| 1062 | .confirm_start = rcsi2_confirm_start_v3m_e3, | 1063 | .phy_post_init = rcsi2_phy_post_init_v3m_e3, |
| 1063 | .num_channels = 4, | 1064 | .num_channels = 4, |
| 1064 | }; | 1065 | }; |
| 1065 | 1066 | ||
| @@ -1072,7 +1073,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { · 6 unmodified lines | |||
| 1072 | 1073 | ||
| 1073 | static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { | 1074 | static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { |
| 1074 | .init_phtw = rcsi2_init_phtw_v3m_e3, | 1075 | .init_phtw = rcsi2_init_phtw_v3m_e3, |
| 1075 | .confirm_start = rcsi2_confirm_start_v3m_e3, | 1076 | .phy_post_init = rcsi2_phy_post_init_v3m_e3, |
| 1076 | .num_channels = 2, | 1077 | .num_channels = 2, |
| 1077 | }; | 1078 | }; |
| 1078 | 1079 | ||
| @@ -85,6 +85,7 @@ · 84 unmodified lines | |||
| 85 | #define VNMC_INF_YUV8_BT601 (1 << 16) | 85 | #define VNMC_INF_YUV8_BT601 (1 << 16) |
| 86 | #define VNMC_INF_YUV10_BT656 (2 << 16) | 86 | #define VNMC_INF_YUV10_BT656 (2 << 16) |
| 87 | #define VNMC_INF_YUV10_BT601 (3 << 16) | 87 | #define VNMC_INF_YUV10_BT601 (3 << 16) |
| 88 | #define VNMC_INF_RAW8 (4 << 16) | ||
| 88 | #define VNMC_INF_YUV16 (5 << 16) | 89 | #define VNMC_INF_YUV16 (5 << 16) |
| 89 | #define VNMC_INF_RGB888 (6 << 16) | 90 | #define VNMC_INF_RGB888 (6 << 16) |
| 90 | #define VNMC_VUP (1 << 10) | 91 | #define VNMC_VUP (1 << 10) |
| @@ -587,13 +588,19 @@ void rvin_crop_scale_comp(struct rvin_dev *vin) · 496 unmodified lines | |||
| 587 | rvin_write(vin, vin->crop.top, VNSLPRC_REG); | 588 | rvin_write(vin, vin->crop.top, VNSLPRC_REG); |
| 588 | rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG); | 589 | rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG); |
| 589 | 590 | ||
| 590 | |||
| 591 | /* TODO: Add support for the UDS scaler. */ | 591 | /* TODO: Add support for the UDS scaler. */ |
| 592 | if (vin->info->model != RCAR_GEN3) | 592 | if (vin->info->model != RCAR_GEN3) |
| 593 | rvin_crop_scale_comp_gen2(vin); | 593 | rvin_crop_scale_comp_gen2(vin); |
| 594 | 594 | ||
| 595 | fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); | 595 | fmt = rvin_format_from_pixel(vin, vin->format.pixelformat); |
| 596 | stride = vin->format.bytesperline / fmt->bpp; | 596 | stride = vin->format.bytesperline / fmt->bpp; |
| 597 | |||
| 598 | /* For RAW8 format bpp is 1, but the hardware process RAW8 | ||
| 599 | * format in 2 pixel unit hence configure VNIS_REG as stride / 2. | ||
| 600 | */ | ||
| 601 | if (vin->format.pixelformat == V4L2_PIX_FMT_SRGGB8) | ||
| 602 | stride /= 2; | ||
| 603 | |||
| 597 | rvin_write(vin, stride, VNIS_REG); | 604 | rvin_write(vin, stride, VNIS_REG); |
| 598 | } | 605 | } |
| 599 | 606 | ||
| @@ -676,6 +683,9 @@ static int rvin_setup(struct rvin_dev *vin) · 76 unmodified lines | |||
| 676 | 683 | ||
| 677 | input_is_yuv = true; | 684 | input_is_yuv = true; |
| 678 | break; | 685 | break; |
| 686 | case MEDIA_BUS_FMT_SRGGB8_1X8: | ||
| 687 | vnmc |= VNMC_INF_RAW8; | ||
| 688 | break; | ||
| 679 | default: | 689 | default: |
| 680 | break; | 690 | break; |
| 681 | } | 691 | } |
| @@ -737,6 +747,9 @@ static int rvin_setup(struct rvin_dev *vin) · 55 unmodified lines | |||
| 737 | case V4L2_PIX_FMT_ABGR32: | 747 | case V4L2_PIX_FMT_ABGR32: |
| 738 | dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB; | 748 | dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB; |
| 739 | break; | 749 | break; |
| 750 | case V4L2_PIX_FMT_SRGGB8: | ||
| 751 | dmr = 0; | ||
| 752 | break; | ||
| 740 | default: | 753 | default: |
| 741 | vin_err(vin, "Invalid pixelformat (0x%x)\n", | 754 | vin_err(vin, "Invalid pixelformat (0x%x)\n", |
| 742 | vin->format.pixelformat); | 755 | vin->format.pixelformat); |
| @@ -1110,11 +1123,15 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, · 367 unmodified lines | |||
| 1110 | case MEDIA_BUS_FMT_UYVY8_2X8: | 1123 | case MEDIA_BUS_FMT_UYVY8_2X8: |
| 1111 | case MEDIA_BUS_FMT_UYVY10_2X10: | 1124 | case MEDIA_BUS_FMT_UYVY10_2X10: |
| 1112 | case MEDIA_BUS_FMT_RGB888_1X24: | 1125 | case MEDIA_BUS_FMT_RGB888_1X24: |
| 1113 | vin->mbus_code = fmt.format.code; | 1126 | break; |
| 1127 | case MEDIA_BUS_FMT_SRGGB8_1X8: | ||
| 1128 | if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8) | ||
| 1129 | return -EPIPE; | ||
| 1114 | break; | 1130 | break; |
| 1115 | default: | 1131 | default: |
| 1116 | return -EPIPE; | 1132 | return -EPIPE; |
| 1117 | } | 1133 | } |
| 1134 | vin->mbus_code = fmt.format.code; | ||
| 1118 | 1135 | ||
| 1119 | switch (fmt.format.field) { | 1136 | switch (fmt.format.field) { |
| 1120 | case V4L2_FIELD_TOP: | 1137 | case V4L2_FIELD_TOP: |
| @@ -66,6 +66,10 @@ static const struct rvin_video_format rvin_formats[] = { · 65 unmodified lines | |||
| 66 | .fourcc = V4L2_PIX_FMT_ABGR32, | 66 | .fourcc = V4L2_PIX_FMT_ABGR32, |
| 67 | .bpp = 4, | 67 | .bpp = 4, |
| 68 | }, | 68 | }, |
| 69 | { | ||
| 70 | .fourcc = V4L2_PIX_FMT_SRGGB8, | ||
| 71 | .bpp = 1, | ||
| 72 | }, | ||
| 69 | }; | 73 | }; |
| 70 | 74 | ||
| 71 | const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, | 75 | const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, |
| @@ -350,9 +354,9 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, · 278 unmodified lines | |||
| 350 | * all of the related pixel formats. If mbus_code is not set enumerate | 354 | * all of the related pixel formats. If mbus_code is not set enumerate |
| 351 | * all possible pixelformats. | 355 | * all possible pixelformats. |
| 352 | * | 356 | * |
| 353 | * TODO: Once raw capture formats are added to the driver this needs | 357 | * TODO: Once raw MEDIA_BUS_FMT_SRGGB12_1X12 format is added to the |
| 354 | * to be extended so raw media bus codes only result in raw pixel | 358 | * driver this needs to be extended so raw media bus code only result in |
| 355 | * formats. | 359 | * raw pixel format. |
| 356 | */ | 360 | */ |
| 357 | switch (f->mbus_code) { | 361 | switch (f->mbus_code) { |
| 358 | case 0: | 362 | case 0: |
| @@ -362,6 +366,11 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, · 3 unmodified lines | |||
| 362 | case MEDIA_BUS_FMT_UYVY10_2X10: | 366 | case MEDIA_BUS_FMT_UYVY10_2X10: |
| 363 | case MEDIA_BUS_FMT_RGB888_1X24: | 367 | case MEDIA_BUS_FMT_RGB888_1X24: |
| 364 | break; | 368 | break; |
| 369 | case MEDIA_BUS_FMT_SRGGB8_1X8: | ||
| 370 | if (f->index) | ||
| 371 | return -EINVAL; | ||
| 372 | f->pixelformat = V4L2_PIX_FMT_SRGGB8; | ||
| 373 | return 0; | ||
| 365 | default: | 374 | default: |
| 366 | return -EINVAL; | 375 | return -EINVAL; |
| 367 | } | 376 | } |
| @@ -1066,7 +1066,7 @@ static int jpu_buf_prepare(struct vb2_buffer *vb) · 1065 unmodified lines | |||
| 1066 | } | 1066 | } |
| 1067 | 1067 | ||
| 1068 | /* decoder capture queue */ | 1068 | /* decoder capture queue */ |
| 1069 | if (!ctx->encoder && !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) | 1069 | if (!ctx->encoder && V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) |
| 1070 | vb2_set_plane_payload(vb, i, size); | 1070 | vb2_set_plane_payload(vb, i, size); |
| 1071 | } | 1071 | } |
| 1072 | 1072 | ||
| @@ -200,22 +200,25 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) · 199 unmodified lines | |||
| 200 | dst_info.data.format = ctx->out.fmt->hw_format; | 200 | dst_info.data.format = ctx->out.fmt->hw_format; |
| 201 | dst_info.data.swap = ctx->out.fmt->color_swap; | 201 | dst_info.data.swap = ctx->out.fmt->color_swap; |
| 202 | 202 | ||
| 203 | if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) { | 203 | /* |
| 204 | if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) { | 204 | * CSC mode must only be set when the colorspace families differ between |
| 205 | switch (ctx->in.colorspace) { | 205 | * input and output. It must remain unset (zeroed) if both are the same. |
| 206 | case V4L2_COLORSPACE_REC709: | 206 | */ |
| 207 | src_info.data.csc_mode = | 207 | |
| 208 | RGA_SRC_CSC_MODE_BT709_R0; | 208 | if (RGA_COLOR_FMT_IS_YUV(ctx->in.fmt->hw_format) && |
| 209 | break; | 209 | RGA_COLOR_FMT_IS_RGB(ctx->out.fmt->hw_format)) { |
| 210 | default: | 210 | switch (ctx->in.colorspace) { |
| 211 | src_info.data.csc_mode = | 211 | case V4L2_COLORSPACE_REC709: |
| 212 | RGA_SRC_CSC_MODE_BT601_R0; | 212 | src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0; |
| 213 | break; | 213 | break; |
| 214 | } | 214 | default: |
| 215 | src_info.data.csc_mode = RGA_SRC_CSC_MODE_BT601_R0; | ||
| 216 | break; | ||
| 215 | } | 217 | } |
| 216 | } | 218 | } |
| 217 | 219 | ||
| 218 | if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) { | 220 | if (RGA_COLOR_FMT_IS_RGB(ctx->in.fmt->hw_format) && |
| 221 | RGA_COLOR_FMT_IS_YUV(ctx->out.fmt->hw_format)) { | ||
| 219 | switch (ctx->out.colorspace) { | 222 | switch (ctx->out.colorspace) { |
| 220 | case V4L2_COLORSPACE_REC709: | 223 | case V4L2_COLORSPACE_REC709: |
| 221 | dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0; | 224 | dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0; |
| @@ -95,6 +95,11 @@ · 94 unmodified lines | |||
| 95 | #define RGA_COLOR_FMT_CP_8BPP 15 | 95 | #define RGA_COLOR_FMT_CP_8BPP 15 |
| 96 | #define RGA_COLOR_FMT_MASK 15 | 96 | #define RGA_COLOR_FMT_MASK 15 |
| 97 | 97 | ||
| 98 | #define RGA_COLOR_FMT_IS_YUV(fmt) \ | ||
| 99 | (((fmt) >= RGA_COLOR_FMT_YUV422SP) && ((fmt) < RGA_COLOR_FMT_CP_1BPP)) | ||
| 100 | #define RGA_COLOR_FMT_IS_RGB(fmt) \ | ||
| 101 | ((fmt) < RGA_COLOR_FMT_YUV422SP) | ||
| 102 | |||
| 98 | #define RGA_COLOR_NONE_SWAP 0 | 103 | #define RGA_COLOR_NONE_SWAP 0 |
| 99 | #define RGA_COLOR_RB_SWAP 1 | 104 | #define RGA_COLOR_RB_SWAP 1 |
| 100 | #define RGA_COLOR_ALPHA_SWAP 2 | 105 | #define RGA_COLOR_ALPHA_SWAP 2 |
| @@ -304,7 +304,7 @@ static int camif_media_dev_init(struct camif_dev *camif) · 303 unmodified lines | |||
| 304 | int ret; | 304 | int ret; |
| 305 | 305 | ||
| 306 | memset(md, 0, sizeof(*md)); | 306 | memset(md, 0, sizeof(*md)); |
| 307 | snprintf(md->model, sizeof(md->model), "SAMSUNG S3C%s CAMIF", | 307 | snprintf(md->model, sizeof(md->model), "Samsung S3C%s CAMIF", |
| 308 | ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X"); | 308 | ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X"); |
| 309 | strscpy(md->bus_info, "platform", sizeof(md->bus_info)); | 309 | strscpy(md->bus_info, "platform", sizeof(md->bus_info)); |
| 310 | md->hw_revision = ip_rev; | 310 | md->hw_revision = ip_rev; |
| @@ -695,21 +695,13 @@ static int g2d_probe(struct platform_device *pdev) · 694 unmodified lines | |||
| 695 | vfd->lock = &dev->mutex; | 695 | vfd->lock = &dev->mutex; |
| 696 | vfd->v4l2_dev = &dev->v4l2_dev; | 696 | vfd->v4l2_dev = &dev->v4l2_dev; |
| 697 | vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; | 697 | vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; |
| 698 | ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | 698 | |
| 699 | if (ret) { | ||
| 700 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
| 701 | goto rel_vdev; | ||
| 702 | } | ||
| 703 | video_set_drvdata(vfd, dev); | ||
| 704 | dev->vfd = vfd; | ||
| 705 | v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", | ||
| 706 | vfd->num); | ||
| 707 | platform_set_drvdata(pdev, dev); | 699 | platform_set_drvdata(pdev, dev); |
| 708 | dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops); | 700 | dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops); |
| 709 | if (IS_ERR(dev->m2m_dev)) { | 701 | if (IS_ERR(dev->m2m_dev)) { |
| 710 | v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); | 702 | v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); |
| 711 | ret = PTR_ERR(dev->m2m_dev); | 703 | ret = PTR_ERR(dev->m2m_dev); |
| 712 | goto unreg_video_dev; | 704 | goto rel_vdev; |
| 713 | } | 705 | } |
| 714 | 706 | ||
| 715 | def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; | 707 | def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; |
| @@ -717,14 +709,24 @@ static int g2d_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 717 | of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); | 709 | of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); |
| 718 | if (!of_id) { | 710 | if (!of_id) { |
| 719 | ret = -ENODEV; | 711 | ret = -ENODEV; |
| 720 | goto unreg_video_dev; | 712 | goto free_m2m; |
| 721 | } | 713 | } |
| 722 | dev->variant = (struct g2d_variant *)of_id->data; | 714 | dev->variant = (struct g2d_variant *)of_id->data; |
| 723 | 715 | ||
| 716 | ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | ||
| 717 | if (ret) { | ||
| 718 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
| 719 | goto free_m2m; | ||
| 720 | } | ||
| 721 | video_set_drvdata(vfd, dev); | ||
| 722 | dev->vfd = vfd; | ||
| 723 | v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", | ||
| 724 | vfd->num); | ||
| 725 | |||
| 724 | return 0; | 726 | return 0; |
| 725 | 727 | ||
| 726 | unreg_video_dev: | 728 | free_m2m: |
| 727 | video_unregister_device(dev->vfd); | 729 | v4l2_m2m_release(dev->m2m_dev); |
| 728 | rel_vdev: | 730 | rel_vdev: |
| 729 | video_device_release(vfd); | 731 | video_device_release(vfd); |
| 730 | unreg_v4l2_dev: | 732 | unreg_v4l2_dev: |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | #include <media/v4l2-event.h> | 24 | #include <media/v4l2-event.h> |
| 25 | #include <media/v4l2-mem2mem.h> | 25 | #include <media/v4l2-mem2mem.h> |
| 26 | #include <media/v4l2-ioctl.h> | 26 | #include <media/v4l2-ioctl.h> |
| 27 | #include <media/v4l2-rect.h> | ||
| 27 | #include <media/videobuf2-v4l2.h> | 28 | #include <media/videobuf2-v4l2.h> |
| 28 | #include <media/videobuf2-dma-contig.h> | 29 | #include <media/videobuf2-dma-contig.h> |
| 29 | 30 | ||
| @@ -1735,19 +1736,6 @@ static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx, · 1705 unmodified lines | |||
| 1735 | return 0; | 1736 | return 0; |
| 1736 | } | 1737 | } |
| 1737 | 1738 | ||
| 1738 | /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ | ||
| 1739 | static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) | ||
| 1740 | { | ||
| 1741 | if (a->left < b->left || a->top < b->top) | ||
| 1742 | return 0; | ||
| 1743 | if (a->left + a->width > b->left + b->width) | ||
| 1744 | return 0; | ||
| 1745 | if (a->top + a->height > b->top + b->height) | ||
| 1746 | return 0; | ||
| 1747 | |||
| 1748 | return 1; | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx, | 1739 | static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx, |
| 1752 | struct v4l2_rect *r) | 1740 | struct v4l2_rect *r) |
| 1753 | { | 1741 | { |
| @@ -1780,7 +1768,7 @@ static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx, · 26 unmodified lines | |||
| 1780 | r->left = round_down(r->left, 2); | 1768 | r->left = round_down(r->left, 2); |
| 1781 | r->top = round_down(r->top, 2); | 1769 | r->top = round_down(r->top, 2); |
| 1782 | 1770 | ||
| 1783 | if (!enclosed_rectangle(r, &base_rect)) | 1771 | if (!v4l2_rect_enclosed(r, &base_rect)) |
| 1784 | return -EINVAL; | 1772 | return -EINVAL; |
| 1785 | 1773 | ||
| 1786 | ctx->crop_rect.left = r->left; | 1774 | ctx->crop_rect.left = r->left; |
| @@ -1087,7 +1087,7 @@ static void hva_stop_streaming(struct vb2_queue *vq) · 1086 unmodified lines | |||
| 1087 | 1087 | ||
| 1088 | if ((V4L2_TYPE_IS_OUTPUT(vq->type) && | 1088 | if ((V4L2_TYPE_IS_OUTPUT(vq->type) && |
| 1089 | vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) || | 1089 | vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) || |
| 1090 | (!V4L2_TYPE_IS_OUTPUT(vq->type) && | 1090 | (V4L2_TYPE_IS_CAPTURE(vq->type) && |
| 1091 | vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))) { | 1091 | vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))) { |
| 1092 | dev_dbg(dev, "%s %s out=%d cap=%d\n", | 1092 | dev_dbg(dev, "%s %s out=%d cap=%d\n", |
| 1093 | ctx->name, to_type_str(vq->type), | 1093 | ctx->name, to_type_str(vq->type), |
| @@ -191,6 +191,8 @@ static int sun4i_csi_probe(struct platform_device *pdev) · 190 unmodified lines | |||
| 191 | strscpy(csi->mdev.model, "Allwinner Video Capture Device", | 191 | strscpy(csi->mdev.model, "Allwinner Video Capture Device", |
| 192 | sizeof(csi->mdev.model)); | 192 | sizeof(csi->mdev.model)); |
| 193 | csi->mdev.hw_revision = 0; | 193 | csi->mdev.hw_revision = 0; |
| 194 | snprintf(csi->mdev.bus_info, sizeof(csi->mdev.bus_info), "platform:%s", | ||
| 195 | dev_name(csi->dev)); | ||
| 194 | media_device_init(&csi->mdev); | 196 | media_device_init(&csi->mdev); |
| 195 | csi->v4l.mdev = &csi->mdev; | 197 | csi->v4l.mdev = &csi->mdev; |
| 196 | 198 | ||
| @@ -413,7 +413,7 @@ int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq) · 412 unmodified lines | |||
| 413 | 413 | ||
| 414 | q->min_buffers_needed = 3; | 414 | q->min_buffers_needed = 3; |
| 415 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 415 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 416 | q->io_modes = VB2_MMAP; | 416 | q->io_modes = VB2_MMAP | VB2_DMABUF; |
| 417 | q->lock = &csi->lock; | 417 | q->lock = &csi->lock; |
| 418 | q->drv_priv = csi; | 418 | q->drv_priv = csi; |
| 419 | q->buf_struct_size = sizeof(struct sun4i_csi_buffer); | 419 | q->buf_struct_size = sizeof(struct sun4i_csi_buffer); |
| @@ -242,7 +242,8 @@ static int sun4i_csi_release(struct file *file) · 241 unmodified lines | |||
| 242 | 242 | ||
| 243 | mutex_lock(&csi->lock); | 243 | mutex_lock(&csi->lock); |
| 244 | 244 | ||
| 245 | v4l2_fh_release(file); | 245 | _vb2_fop_release(file, NULL); |
| 246 | |||
| 246 | v4l2_pipeline_pm_put(&csi->vdev.entity); | 247 | v4l2_pipeline_pm_put(&csi->vdev.entity); |
| 247 | pm_runtime_put(csi->dev); | 248 | pm_runtime_put(csi->dev); |
| 248 | 249 | ||
| @@ -256,8 +257,6 @@ static const struct v4l2_file_operations sun4i_csi_fops = { · 7 unmodified lines | |||
| 256 | .open = sun4i_csi_open, | 257 | .open = sun4i_csi_open, |
| 257 | .release = sun4i_csi_release, | 258 | .release = sun4i_csi_release, |
| 258 | .unlocked_ioctl = video_ioctl2, | 259 | .unlocked_ioctl = video_ioctl2, |
| 259 | .read = vb2_fop_read, | ||
| 260 | .write = vb2_fop_write, | ||
| 261 | .poll = vb2_fop_poll, | 260 | .poll = vb2_fop_poll, |
| 262 | .mmap = vb2_fop_mmap, | 261 | .mmap = vb2_fop_mmap, |
| 263 | }; | 262 | }; |
| @@ -733,6 +733,8 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) · 732 unmodified lines | |||
| 733 | strscpy(csi->media_dev.model, "Allwinner Video Capture Device", | 733 | strscpy(csi->media_dev.model, "Allwinner Video Capture Device", |
| 734 | sizeof(csi->media_dev.model)); | 734 | sizeof(csi->media_dev.model)); |
| 735 | csi->media_dev.hw_revision = 0; | 735 | csi->media_dev.hw_revision = 0; |
| 736 | snprintf(csi->media_dev.bus_info, sizeof(csi->media_dev.bus_info), | ||
| 737 | "platform:%s", dev_name(csi->dev)); | ||
| 736 | 738 | ||
| 737 | media_device_init(&csi->media_dev); | 739 | media_device_init(&csi->media_dev); |
| 738 | v4l2_async_notifier_init(&csi->notifier); | 740 | v4l2_async_notifier_init(&csi->notifier); |
| @@ -13,4 +13,4 @@ ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | obj-$(CONFIG_VIDEO_TI_CAL) += ti-cal.o | 14 | obj-$(CONFIG_VIDEO_TI_CAL) += ti-cal.o |
| 15 | 15 | ||
| 16 | ti-cal-y := cal.o | 16 | ti-cal-y := cal.o cal-camerarx.o cal-video.o |
| @@ -0,0 +1,649 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * TI Camera Access Layer (CAL) - CAMERARX | ||
| 4 | * | ||
| 5 | * Copyright (c) 2015-2020 Texas Instruments Inc. | ||
| 6 | * | ||
| 7 | * Authors: | ||
| 8 | * Benoit Parrot <bparrot@ti.com> | ||
| 9 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/clk.h> | ||
| 13 | #include <linux/delay.h> | ||
| 14 | #include <linux/mfd/syscon.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/of_graph.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/regmap.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | |||
| 21 | #include <media/v4l2-ctrls.h> | ||
| 22 | #include <media/v4l2-fwnode.h> | ||
| 23 | #include <media/v4l2-subdev.h> | ||
| 24 | |||
| 25 | #include "cal.h" | ||
| 26 | #include "cal_regs.h" | ||
| 27 | |||
| 28 | /* ------------------------------------------------------------------ | ||
| 29 | * I/O Register Accessors | ||
| 30 | * ------------------------------------------------------------------ | ||
| 31 | */ | ||
| 32 | |||
| 33 | static inline u32 camerarx_read(struct cal_camerarx *phy, u32 offset) | ||
| 34 | { | ||
| 35 | return ioread32(phy->base + offset); | ||
| 36 | } | ||
| 37 | |||
| 38 | static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val) | ||
| 39 | { | ||
| 40 | iowrite32(val, phy->base + offset); | ||
| 41 | } | ||
| 42 | |||
| 43 | /* ------------------------------------------------------------------ | ||
| 44 | * CAMERARX Management | ||
| 45 | * ------------------------------------------------------------------ | ||
| 46 | */ | ||
| 47 | |||
| 48 | static s64 cal_camerarx_get_external_rate(struct cal_camerarx *phy) | ||
| 49 | { | ||
| 50 | struct v4l2_ctrl *ctrl; | ||
| 51 | s64 rate; | ||
| 52 | |||
| 53 | ctrl = v4l2_ctrl_find(phy->sensor->ctrl_handler, V4L2_CID_PIXEL_RATE); | ||
| 54 | if (!ctrl) { | ||
| 55 | phy_err(phy, "no pixel rate control in subdev: %s\n", | ||
| 56 | phy->sensor->name); | ||
| 57 | return -EPIPE; | ||
| 58 | } | ||
| 59 | |||
| 60 | rate = v4l2_ctrl_g_ctrl_int64(ctrl); | ||
| 61 | phy_dbg(3, phy, "sensor Pixel Rate: %llu\n", rate); | ||
| 62 | |||
| 63 | return rate; | ||
| 64 | } | ||
| 65 | |||
| 66 | static void cal_camerarx_lane_config(struct cal_camerarx *phy) | ||
| 67 | { | ||
| 68 | u32 val = cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)); | ||
| 69 | u32 lane_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK; | ||
| 70 | u32 polarity_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK; | ||
| 71 | struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = | ||
| 72 | &phy->endpoint.bus.mipi_csi2; | ||
| 73 | int lane; | ||
| 74 | |||
| 75 | cal_set_field(&val, mipi_csi2->clock_lane + 1, lane_mask); | ||
| 76 | cal_set_field(&val, mipi_csi2->lane_polarities[0], polarity_mask); | ||
| 77 | for (lane = 0; lane < mipi_csi2->num_data_lanes; lane++) { | ||
| 78 | /* | ||
| 79 | * Every lane are one nibble apart starting with the | ||
| 80 | * clock followed by the data lanes so shift masks by 4. | ||
| 81 | */ | ||
| 82 | lane_mask <<= 4; | ||
| 83 | polarity_mask <<= 4; | ||
| 84 | cal_set_field(&val, mipi_csi2->data_lanes[lane] + 1, lane_mask); | ||
| 85 | cal_set_field(&val, mipi_csi2->lane_polarities[lane + 1], | ||
| 86 | polarity_mask); | ||
| 87 | } | ||
| 88 | |||
| 89 | cal_write(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), val); | ||
| 90 | phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n", | ||
| 91 | phy->instance, val); | ||
| 92 | } | ||
| 93 | |||
| 94 | static void cal_camerarx_enable(struct cal_camerarx *phy) | ||
| 95 | { | ||
| 96 | u32 num_lanes = phy->cal->data->camerarx[phy->instance].num_lanes; | ||
| 97 | |||
| 98 | regmap_field_write(phy->fields[F_CAMMODE], 0); | ||
| 99 | /* Always enable all lanes at the phy control level */ | ||
| 100 | regmap_field_write(phy->fields[F_LANEENABLE], (1 << num_lanes) - 1); | ||
| 101 | /* F_CSI_MODE is not present on every architecture */ | ||
| 102 | if (phy->fields[F_CSI_MODE]) | ||
| 103 | regmap_field_write(phy->fields[F_CSI_MODE], 1); | ||
| 104 | regmap_field_write(phy->fields[F_CTRLCLKEN], 1); | ||
| 105 | } | ||
| 106 | |||
| 107 | void cal_camerarx_disable(struct cal_camerarx *phy) | ||
| 108 | { | ||
| 109 | regmap_field_write(phy->fields[F_CTRLCLKEN], 0); | ||
| 110 | } | ||
| 111 | |||
| 112 | /* | ||
| 113 | * TCLK values are OK at their reset values | ||
| 114 | */ | ||
| 115 | #define TCLK_TERM 0 | ||
| 116 | #define TCLK_MISS 1 | ||
| 117 | #define TCLK_SETTLE 14 | ||
| 118 | |||
| 119 | static void cal_camerarx_config(struct cal_camerarx *phy, s64 external_rate, | ||
| 120 | const struct cal_fmt *fmt) | ||
| 121 | { | ||
| 122 | unsigned int reg0, reg1; | ||
| 123 | unsigned int ths_term, ths_settle; | ||
| 124 | unsigned int csi2_ddrclk_khz; | ||
| 125 | struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = | ||
| 126 | &phy->endpoint.bus.mipi_csi2; | ||
| 127 | u32 num_lanes = mipi_csi2->num_data_lanes; | ||
| 128 | |||
| 129 | /* DPHY timing configuration */ | ||
| 130 | |||
| 131 | /* | ||
| 132 | * CSI-2 is DDR and we only count used lanes. | ||
| 133 | * | ||
| 134 | * csi2_ddrclk_khz = external_rate / 1000 | ||
| 135 | * / (2 * num_lanes) * fmt->bpp; | ||
| 136 | */ | ||
| 137 | csi2_ddrclk_khz = div_s64(external_rate * fmt->bpp, | ||
| 138 | 2 * num_lanes * 1000); | ||
| 139 | |||
| 140 | phy_dbg(1, phy, "csi2_ddrclk_khz: %d\n", csi2_ddrclk_khz); | ||
| 141 | |||
| 142 | /* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */ | ||
| 143 | ths_term = 20 * csi2_ddrclk_khz / 1000000; | ||
| 144 | phy_dbg(1, phy, "ths_term: %d (0x%02x)\n", ths_term, ths_term); | ||
| 145 | |||
| 146 | /* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */ | ||
| 147 | ths_settle = (105 * csi2_ddrclk_khz / 1000000) + 4; | ||
| 148 | phy_dbg(1, phy, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle); | ||
| 149 | |||
| 150 | reg0 = camerarx_read(phy, CAL_CSI2_PHY_REG0); | ||
| 151 | cal_set_field(®0, CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE, | ||
| 152 | CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK); | ||
| 153 | cal_set_field(®0, ths_term, CAL_CSI2_PHY_REG0_THS_TERM_MASK); | ||
| 154 | cal_set_field(®0, ths_settle, CAL_CSI2_PHY_REG0_THS_SETTLE_MASK); | ||
| 155 | |||
| 156 | phy_dbg(1, phy, "CSI2_%d_REG0 = 0x%08x\n", phy->instance, reg0); | ||
| 157 | camerarx_write(phy, CAL_CSI2_PHY_REG0, reg0); | ||
| 158 | |||
| 159 | reg1 = camerarx_read(phy, CAL_CSI2_PHY_REG1); | ||
| 160 | cal_set_field(®1, TCLK_TERM, CAL_CSI2_PHY_REG1_TCLK_TERM_MASK); | ||
| 161 | cal_set_field(®1, 0xb8, CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK); | ||
| 162 | cal_set_field(®1, TCLK_MISS, | ||
| 163 | CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK); | ||
| 164 | cal_set_field(®1, TCLK_SETTLE, CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK); | ||
| 165 | |||
| 166 | phy_dbg(1, phy, "CSI2_%d_REG1 = 0x%08x\n", phy->instance, reg1); | ||
| 167 | camerarx_write(phy, CAL_CSI2_PHY_REG1, reg1); | ||
| 168 | } | ||
| 169 | |||
| 170 | static void cal_camerarx_power(struct cal_camerarx *phy, bool enable) | ||
| 171 | { | ||
| 172 | u32 target_state; | ||
| 173 | unsigned int i; | ||
| 174 | |||
| 175 | target_state = enable ? CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON : | ||
| 176 | CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF; | ||
| 177 | |||
| 178 | cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), | ||
| 179 | target_state, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK); | ||
| 180 | |||
| 181 | for (i = 0; i < 10; i++) { | ||
| 182 | u32 current_state; | ||
| 183 | |||
| 184 | current_state = cal_read_field(phy->cal, | ||
| 185 | CAL_CSI2_COMPLEXIO_CFG(phy->instance), | ||
| 186 | CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK); | ||
| 187 | |||
| 188 | if (current_state == target_state) | ||
| 189 | break; | ||
| 190 | |||
| 191 | usleep_range(1000, 1100); | ||
| 192 | } | ||
| 193 | |||
| 194 | if (i == 10) | ||
| 195 | phy_err(phy, "Failed to power %s complexio\n", | ||
| 196 | enable ? "up" : "down"); | ||
| 197 | } | ||
| 198 | |||
| 199 | static void cal_camerarx_wait_reset(struct cal_camerarx *phy) | ||
| 200 | { | ||
| 201 | unsigned long timeout; | ||
| 202 | |||
| 203 | timeout = jiffies + msecs_to_jiffies(750); | ||
| 204 | while (time_before(jiffies, timeout)) { | ||
| 205 | if (cal_read_field(phy->cal, | ||
| 206 | CAL_CSI2_COMPLEXIO_CFG(phy->instance), | ||
| 207 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == | ||
| 208 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) | ||
| 209 | break; | ||
| 210 | usleep_range(500, 5000); | ||
| 211 | } | ||
| 212 | |||
| 213 | if (cal_read_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), | ||
| 214 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) != | ||
| 215 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) | ||
| 216 | phy_err(phy, "Timeout waiting for Complex IO reset done\n"); | ||
| 217 | } | ||
| 218 | |||
| 219 | static void cal_camerarx_wait_stop_state(struct cal_camerarx *phy) | ||
| 220 | { | ||
| 221 | unsigned long timeout; | ||
| 222 | |||
| 223 | timeout = jiffies + msecs_to_jiffies(750); | ||
| 224 | while (time_before(jiffies, timeout)) { | ||
| 225 | if (cal_read_field(phy->cal, | ||
| 226 | CAL_CSI2_TIMING(phy->instance), | ||
| 227 | CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) == 0) | ||
| 228 | break; | ||
| 229 | usleep_range(500, 5000); | ||
| 230 | } | ||
| 231 | |||
| 232 | if (cal_read_field(phy->cal, CAL_CSI2_TIMING(phy->instance), | ||
| 233 | CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) != 0) | ||
| 234 | phy_err(phy, "Timeout waiting for stop state\n"); | ||
| 235 | } | ||
| 236 | |||
| 237 | int cal_camerarx_start(struct cal_camerarx *phy, const struct cal_fmt *fmt) | ||
| 238 | { | ||
| 239 | s64 external_rate; | ||
| 240 | u32 sscounter; | ||
| 241 | u32 val; | ||
| 242 | int ret; | ||
| 243 | |||
| 244 | external_rate = cal_camerarx_get_external_rate(phy); | ||
| 245 | if (external_rate < 0) | ||
| 246 | return external_rate; | ||
| 247 | |||
| 248 | ret = v4l2_subdev_call(phy->sensor, core, s_power, 1); | ||
| 249 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { | ||
| 250 | phy_err(phy, "power on failed in subdev\n"); | ||
| 251 | return ret; | ||
| 252 | } | ||
| 253 | |||
| 254 | /* | ||
| 255 | * CSI-2 PHY Link Initialization Sequence, according to the DRA74xP / | ||
| 256 | * DRA75xP / DRA76xP / DRA77xP TRM. The DRA71x / DRA72x and the AM65x / | ||
| 257 | * DRA80xM TRMs have a a slightly simplified sequence. | ||
| 258 | */ | ||
| 259 | |||
| 260 | /* | ||
| 261 | * 1. Configure all CSI-2 low level protocol registers to be ready to | ||
| 262 | * receive signals/data from the CSI-2 PHY. | ||
| 263 | * | ||
| 264 | * i.-v. Configure the lanes position and polarity. | ||
| 265 | */ | ||
| 266 | cal_camerarx_lane_config(phy); | ||
| 267 | |||
| 268 | /* | ||
| 269 | * vi.-vii. Configure D-PHY mode, enable the required lanes and | ||
| 270 | * enable the CAMERARX clock. | ||
| 271 | */ | ||
| 272 | cal_camerarx_enable(phy); | ||
| 273 | |||
| 274 | /* | ||
| 275 | * 2. CSI PHY and link initialization sequence. | ||
| 276 | * | ||
| 277 | * a. Deassert the CSI-2 PHY reset. Do not wait for reset completion | ||
| 278 | * at this point, as it requires the external sensor to send the | ||
| 279 | * CSI-2 HS clock. | ||
| 280 | */ | ||
| 281 | cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), | ||
| 282 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL, | ||
| 283 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); | ||
| 284 | phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x De-assert Complex IO Reset\n", | ||
| 285 | phy->instance, | ||
| 286 | cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance))); | ||
| 287 | |||
| 288 | /* Dummy read to allow SCP reset to complete. */ | ||
| 289 | camerarx_read(phy, CAL_CSI2_PHY_REG0); | ||
| 290 | |||
| 291 | /* Program the PHY timing parameters. */ | ||
| 292 | cal_camerarx_config(phy, external_rate, fmt); | ||
| 293 | |||
| 294 | /* | ||
| 295 | * b. Assert the FORCERXMODE signal. | ||
| 296 | * | ||
| 297 | * The stop-state-counter is based on fclk cycles, and we always use | ||
| 298 | * the x16 and x4 settings, so stop-state-timeout = | ||
| 299 | * fclk-cycle * 16 * 4 * counter. | ||
| 300 | * | ||
| 301 | * Stop-state-timeout must be more than 100us as per CSI-2 spec, so we | ||
| 302 | * calculate a timeout that's 100us (rounding up). | ||
| 303 | */ | ||
| 304 | sscounter = DIV_ROUND_UP(clk_get_rate(phy->cal->fclk), 10000 * 16 * 4); | ||
| 305 | |||
| 306 | val = cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance)); | ||
| 307 | cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK); | ||
| 308 | cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK); | ||
| 309 | cal_set_field(&val, sscounter, | ||
| 310 | CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK); | ||
| 311 | cal_write(phy->cal, CAL_CSI2_TIMING(phy->instance), val); | ||
| 312 | phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Stop States\n", | ||
| 313 | phy->instance, | ||
| 314 | cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance))); | ||
| 315 | |||
| 316 | /* Assert the FORCERXMODE signal. */ | ||
| 317 | cal_write_field(phy->cal, CAL_CSI2_TIMING(phy->instance), | ||
| 318 | 1, CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK); | ||
| 319 | phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Force RXMODE\n", | ||
| 320 | phy->instance, | ||
| 321 | cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance))); | ||
| 322 | |||
| 323 | /* | ||
| 324 | * c. Connect pull-down on CSI-2 PHY link (using pad control). | ||
| 325 | * | ||
| 326 | * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not | ||
| 327 | * implemented. | ||
| 328 | */ | ||
| 329 | |||
| 330 | /* | ||
| 331 | * d. Power up the CSI-2 PHY. | ||
| 332 | * e. Check whether the state status reaches the ON state. | ||
| 333 | */ | ||
| 334 | cal_camerarx_power(phy, true); | ||
| 335 | |||
| 336 | /* | ||
| 337 | * Start the sensor to enable the CSI-2 HS clock. We can now wait for | ||
| 338 | * CSI-2 PHY reset to complete. | ||
| 339 | */ | ||
| 340 | ret = v4l2_subdev_call(phy->sensor, video, s_stream, 1); | ||
| 341 | if (ret) { | ||
| 342 | v4l2_subdev_call(phy->sensor, core, s_power, 0); | ||
| 343 | phy_err(phy, "stream on failed in subdev\n"); | ||
| 344 | return ret; | ||
| 345 | } | ||
| 346 | |||
| 347 | cal_camerarx_wait_reset(phy); | ||
| 348 | |||
| 349 | /* f. Wait for STOPSTATE=1 for all enabled lane modules. */ | ||
| 350 | cal_camerarx_wait_stop_state(phy); | ||
| 351 | |||
| 352 | phy_dbg(1, phy, "CSI2_%u_REG1 = 0x%08x (bits 31-28 should be set)\n", | ||
| 353 | phy->instance, camerarx_read(phy, CAL_CSI2_PHY_REG1)); | ||
| 354 | |||
| 355 | /* | ||
| 356 | * g. Disable pull-down on CSI-2 PHY link (using pad control). | ||
| 357 | * | ||
| 358 | * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not | ||
| 359 | * implemented. | ||
| 360 | */ | ||
| 361 | |||
| 362 | return 0; | ||
| 363 | } | ||
| 364 | |||
| 365 | void cal_camerarx_stop(struct cal_camerarx *phy) | ||
| 366 | { | ||
| 367 | unsigned int i; | ||
| 368 | int ret; | ||
| 369 | |||
| 370 | cal_camerarx_power(phy, false); | ||
| 371 | |||
| 372 | /* Assert Complex IO Reset */ | ||
| 373 | cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), | ||
| 374 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL, | ||
| 375 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); | ||
| 376 | |||
| 377 | /* Wait for power down completion */ | ||
| 378 | for (i = 0; i < 10; i++) { | ||
| 379 | if (cal_read_field(phy->cal, | ||
| 380 | CAL_CSI2_COMPLEXIO_CFG(phy->instance), | ||
| 381 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == | ||
| 382 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING) | ||
| 383 | break; | ||
| 384 | usleep_range(1000, 1100); | ||
| 385 | } | ||
| 386 | phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset (%d) %s\n", | ||
| 387 | phy->instance, | ||
| 388 | cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)), i, | ||
| 389 | (i >= 10) ? "(timeout)" : ""); | ||
| 390 | |||
| 391 | /* Disable the phy */ | ||
| 392 | cal_camerarx_disable(phy); | ||
| 393 | |||
| 394 | if (v4l2_subdev_call(phy->sensor, video, s_stream, 0)) | ||
| 395 | phy_err(phy, "stream off failed in subdev\n"); | ||
| 396 | |||
| 397 | ret = v4l2_subdev_call(phy->sensor, core, s_power, 0); | ||
| 398 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
| 399 | phy_err(phy, "power off failed in subdev\n"); | ||
| 400 | } | ||
| 401 | |||
| 402 | /* | ||
| 403 | * Errata i913: CSI2 LDO Needs to be disabled when module is powered on | ||
| 404 | * | ||
| 405 | * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2 | ||
| 406 | * LDOs on the device are disabled if CSI-2 module is powered on | ||
| 407 | * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304 | ||
| 408 | * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high | ||
| 409 | * current draw on the module supply in active mode. | ||
| 410 | * | ||
| 411 | * Errata does not apply when CSI-2 module is powered off | ||
| 412 | * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0). | ||
| 413 | * | ||
| 414 | * SW Workaround: | ||
| 415 | * Set the following register bits to disable the LDO, | ||
| 416 | * which is essentially CSI2 REG10 bit 6: | ||
| 417 | * | ||
| 418 | * Core 0: 0x4845 B828 = 0x0000 0040 | ||
| 419 | * Core 1: 0x4845 B928 = 0x0000 0040 | ||
| 420 | */ | ||
| 421 | void cal_camerarx_i913_errata(struct cal_camerarx *phy) | ||
| 422 | { | ||
| 423 | u32 reg10 = camerarx_read(phy, CAL_CSI2_PHY_REG10); | ||
| 424 | |||
| 425 | cal_set_field(®10, 1, CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK); | ||
| 426 | |||
| 427 | phy_dbg(1, phy, "CSI2_%d_REG10 = 0x%08x\n", phy->instance, reg10); | ||
| 428 | camerarx_write(phy, CAL_CSI2_PHY_REG10, reg10); | ||
| 429 | } | ||
| 430 | |||
| 431 | /* | ||
| 432 | * Enable the expected IRQ sources | ||
| 433 | */ | ||
| 434 | void cal_camerarx_enable_irqs(struct cal_camerarx *phy) | ||
| 435 | { | ||
| 436 | u32 val; | ||
| 437 | |||
| 438 | const u32 cio_err_mask = | ||
| 439 | CAL_CSI2_COMPLEXIO_IRQ_LANE_ERRORS_MASK | | ||
| 440 | CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK | | ||
| 441 | CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK | | ||
| 442 | CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK; | ||
| 443 | |||
| 444 | /* Enable CIO error irqs */ | ||
| 445 | cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0), | ||
| 446 | CAL_HL_IRQ_CIO_MASK(phy->instance)); | ||
| 447 | cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), | ||
| 448 | cio_err_mask); | ||
| 449 | |||
| 450 | /* Always enable OCPO error */ | ||
| 451 | cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK); | ||
| 452 | |||
| 453 | /* Enable IRQ_WDMA_END 0/1 */ | ||
| 454 | val = 0; | ||
| 455 | cal_set_field(&val, 1, CAL_HL_IRQ_MASK(phy->instance)); | ||
| 456 | cal_write(phy->cal, CAL_HL_IRQENABLE_SET(1), val); | ||
| 457 | /* Enable IRQ_WDMA_START 0/1 */ | ||
| 458 | val = 0; | ||
| 459 | cal_set_field(&val, 1, CAL_HL_IRQ_MASK(phy->instance)); | ||
| 460 | cal_write(phy->cal, CAL_HL_IRQENABLE_SET(2), val); | ||
| 461 | /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */ | ||
| 462 | cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(0), 0xFF000000); | ||
| 463 | } | ||
| 464 | |||
| 465 | void cal_camerarx_disable_irqs(struct cal_camerarx *phy) | ||
| 466 | { | ||
| 467 | u32 val; | ||
| 468 | |||
| 469 | /* Disable CIO error irqs */ | ||
| 470 | cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(0), | ||
| 471 | CAL_HL_IRQ_CIO_MASK(phy->instance)); | ||
| 472 | cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), 0); | ||
| 473 | |||
| 474 | /* Disable IRQ_WDMA_END 0/1 */ | ||
| 475 | val = 0; | ||
| 476 | cal_set_field(&val, 1, CAL_HL_IRQ_MASK(phy->instance)); | ||
| 477 | cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(1), val); | ||
| 478 | /* Disable IRQ_WDMA_START 0/1 */ | ||
| 479 | val = 0; | ||
| 480 | cal_set_field(&val, 1, CAL_HL_IRQ_MASK(phy->instance)); | ||
| 481 | cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(2), val); | ||
| 482 | /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */ | ||
| 483 | cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(0), 0); | ||
| 484 | } | ||
| 485 | |||
| 486 | void cal_camerarx_ppi_enable(struct cal_camerarx *phy) | ||
| 487 | { | ||
| 488 | cal_write(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), BIT(3)); | ||
| 489 | cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), | ||
| 490 | 1, CAL_CSI2_PPI_CTRL_IF_EN_MASK); | ||
| 491 | } | ||
| 492 | |||
| 493 | void cal_camerarx_ppi_disable(struct cal_camerarx *phy) | ||
| 494 | { | ||
| 495 | cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), | ||
| 496 | 0, CAL_CSI2_PPI_CTRL_IF_EN_MASK); | ||
| 497 | } | ||
| 498 | |||
| 499 | static int cal_camerarx_regmap_init(struct cal_dev *cal, | ||
| 500 | struct cal_camerarx *phy) | ||
| 501 | { | ||
| 502 | const struct cal_camerarx_data *phy_data; | ||
| 503 | unsigned int i; | ||
| 504 | |||
| 505 | if (!cal->data) | ||
| 506 | return -EINVAL; | ||
| 507 | |||
| 508 | phy_data = &cal->data->camerarx[phy->instance]; | ||
| 509 | |||
| 510 | for (i = 0; i < F_MAX_FIELDS; i++) { | ||
| 511 | struct reg_field field = { | ||
| 512 | .reg = cal->syscon_camerrx_offset, | ||
| 513 | .lsb = phy_data->fields[i].lsb, | ||
| 514 | .msb = phy_data->fields[i].msb, | ||
| 515 | }; | ||
| 516 | |||
| 517 | /* | ||
| 518 | * Here we update the reg offset with the | ||
| 519 | * value found in DT | ||
| 520 | */ | ||
| 521 | phy->fields[i] = devm_regmap_field_alloc(cal->dev, | ||
| 522 | cal->syscon_camerrx, | ||
| 523 | field); | ||
| 524 | if (IS_ERR(phy->fields[i])) { | ||
| 525 | cal_err(cal, "Unable to allocate regmap fields\n"); | ||
| 526 | return PTR_ERR(phy->fields[i]); | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | return 0; | ||
| 531 | } | ||
| 532 | |||
| 533 | static int cal_camerarx_parse_dt(struct cal_camerarx *phy) | ||
| 534 | { | ||
| 535 | struct v4l2_fwnode_endpoint *endpoint = &phy->endpoint; | ||
| 536 | struct device_node *ep_node; | ||
| 537 | char data_lanes[V4L2_FWNODE_CSI2_MAX_DATA_LANES * 2]; | ||
| 538 | unsigned int i; | ||
| 539 | int ret; | ||
| 540 | |||
| 541 | /* | ||
| 542 | * Find the endpoint node for the port corresponding to the PHY | ||
| 543 | * instance, and parse its CSI-2-related properties. | ||
| 544 | */ | ||
| 545 | ep_node = of_graph_get_endpoint_by_regs(phy->cal->dev->of_node, | ||
| 546 | phy->instance, 0); | ||
| 547 | if (!ep_node) { | ||
| 548 | /* | ||
| 549 | * The endpoint is not mandatory, not all PHY instances need to | ||
| 550 | * be connected in DT. | ||
| 551 | */ | ||
| 552 | phy_dbg(3, phy, "Port has no endpoint\n"); | ||
| 553 | return 0; | ||
| 554 | } | ||
| 555 | |||
| 556 | endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; | ||
| 557 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint); | ||
| 558 | if (ret < 0) { | ||
| 559 | phy_err(phy, "Failed to parse endpoint\n"); | ||
| 560 | goto done; | ||
| 561 | } | ||
| 562 | |||
| 563 | for (i = 0; i < endpoint->bus.mipi_csi2.num_data_lanes; i++) { | ||
| 564 | unsigned int lane = endpoint->bus.mipi_csi2.data_lanes[i]; | ||
| 565 | |||
| 566 | if (lane > 4) { | ||
| 567 | phy_err(phy, "Invalid position %u for data lane %u\n", | ||
| 568 | lane, i); | ||
| 569 | ret = -EINVAL; | ||
| 570 | goto done; | ||
| 571 | } | ||
| 572 | |||
| 573 | data_lanes[i*2] = '0' + lane; | ||
| 574 | data_lanes[i*2+1] = ' '; | ||
| 575 | } | ||
| 576 | |||
| 577 | data_lanes[i*2-1] = '\0'; | ||
| 578 | |||
| 579 | phy_dbg(3, phy, | ||
| 580 | "CSI-2 bus: clock lane <%u>, data lanes <%s>, flags 0x%08x\n", | ||
| 581 | endpoint->bus.mipi_csi2.clock_lane, data_lanes, | ||
| 582 | endpoint->bus.mipi_csi2.flags); | ||
| 583 | |||
| 584 | /* Retrieve the connected device and store it for later use. */ | ||
| 585 | phy->sensor_node = of_graph_get_remote_port_parent(ep_node); | ||
| 586 | if (!phy->sensor_node) { | ||
| 587 | phy_dbg(3, phy, "Can't get remote parent\n"); | ||
| 588 | ret = -EINVAL; | ||
| 589 | goto done; | ||
| 590 | } | ||
| 591 | |||
| 592 | phy_dbg(1, phy, "Found connected device %pOFn\n", phy->sensor_node); | ||
| 593 | |||
| 594 | done: | ||
| 595 | of_node_put(ep_node); | ||
| 596 | return ret; | ||
| 597 | } | ||
| 598 | |||
| 599 | struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, | ||
| 600 | unsigned int instance) | ||
| 601 | { | ||
| 602 | struct platform_device *pdev = to_platform_device(cal->dev); | ||
| 603 | struct cal_camerarx *phy; | ||
| 604 | int ret; | ||
| 605 | |||
| 606 | phy = kzalloc(sizeof(*phy), GFP_KERNEL); | ||
| 607 | if (!phy) | ||
| 608 | return ERR_PTR(-ENOMEM); | ||
| 609 | |||
| 610 | phy->cal = cal; | ||
| 611 | phy->instance = instance; | ||
| 612 | |||
| 613 | phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
| 614 | (instance == 0) ? | ||
| 615 | "cal_rx_core0" : | ||
| 616 | "cal_rx_core1"); | ||
| 617 | phy->base = devm_ioremap_resource(cal->dev, phy->res); | ||
| 618 | if (IS_ERR(phy->base)) { | ||
| 619 | cal_err(cal, "failed to ioremap\n"); | ||
| 620 | ret = PTR_ERR(phy->base); | ||
| 621 | goto error; | ||
| 622 | } | ||
| 623 | |||
| 624 | cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", | ||
| 625 | phy->res->name, &phy->res->start, &phy->res->end); | ||
| 626 | |||
| 627 | ret = cal_camerarx_regmap_init(cal, phy); | ||
| 628 | if (ret) | ||
| 629 | goto error; | ||
| 630 | |||
| 631 | ret = cal_camerarx_parse_dt(phy); | ||
| 632 | if (ret) | ||
| 633 | goto error; | ||
| 634 | |||
| 635 | return phy; | ||
| 636 | |||
| 637 | error: | ||
| 638 | kfree(phy); | ||
| 639 | return ERR_PTR(ret); | ||
| 640 | } | ||
| 641 | |||
| 642 | void cal_camerarx_destroy(struct cal_camerarx *phy) | ||
| 643 | { | ||
| 644 | if (!phy) | ||
| 645 | return; | ||
| 646 | |||
| 647 | of_node_put(phy->sensor_node); | ||
| 648 | kfree(phy); | ||
| 649 | } | ||
| @@ -0,0 +1,886 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * TI Camera Access Layer (CAL) - Video Device | ||
| 4 | * | ||
| 5 | * Copyright (c) 2015-2020 Texas Instruments Inc. | ||
| 6 | * | ||
| 7 | * Authors: | ||
| 8 | * Benoit Parrot <bparrot@ti.com> | ||
| 9 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/ioctl.h> | ||
| 14 | #include <linux/pm_runtime.h> | ||
| 15 | #include <linux/videodev2.h> | ||
| 16 | |||
| 17 | #include <media/media-device.h> | ||
| 18 | #include <media/v4l2-common.h> | ||
| 19 | #include <media/v4l2-ctrls.h> | ||
| 20 | #include <media/v4l2-device.h> | ||
| 21 | #include <media/v4l2-event.h> | ||
| 22 | #include <media/v4l2-fh.h> | ||
| 23 | #include <media/v4l2-ioctl.h> | ||
| 24 | #include <media/videobuf2-core.h> | ||
| 25 | #include <media/videobuf2-dma-contig.h> | ||
| 26 | |||
| 27 | #include "cal.h" | ||
| 28 | |||
| 29 | /* ------------------------------------------------------------------ | ||
| 30 | * Format Handling | ||
| 31 | * ------------------------------------------------------------------ | ||
| 32 | */ | ||
| 33 | |||
| 34 | static const struct cal_fmt cal_formats[] = { | ||
| 35 | { | ||
| 36 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
| 37 | .code = MEDIA_BUS_FMT_YUYV8_2X8, | ||
| 38 | .bpp = 16, | ||
| 39 | }, { | ||
| 40 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
| 41 | .code = MEDIA_BUS_FMT_UYVY8_2X8, | ||
| 42 | .bpp = 16, | ||
| 43 | }, { | ||
| 44 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
| 45 | .code = MEDIA_BUS_FMT_YVYU8_2X8, | ||
| 46 | .bpp = 16, | ||
| 47 | }, { | ||
| 48 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
| 49 | .code = MEDIA_BUS_FMT_VYUY8_2X8, | ||
| 50 | .bpp = 16, | ||
| 51 | }, { | ||
| 52 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | ||
| 53 | .code = MEDIA_BUS_FMT_RGB565_2X8_LE, | ||
| 54 | .bpp = 16, | ||
| 55 | }, { | ||
| 56 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ | ||
| 57 | .code = MEDIA_BUS_FMT_RGB565_2X8_BE, | ||
| 58 | .bpp = 16, | ||
| 59 | }, { | ||
| 60 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ | ||
| 61 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, | ||
| 62 | .bpp = 16, | ||
| 63 | }, { | ||
| 64 | .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ | ||
| 65 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, | ||
| 66 | .bpp = 16, | ||
| 67 | }, { | ||
| 68 | .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ | ||
| 69 | .code = MEDIA_BUS_FMT_RGB888_2X12_LE, | ||
| 70 | .bpp = 24, | ||
| 71 | }, { | ||
| 72 | .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ | ||
| 73 | .code = MEDIA_BUS_FMT_RGB888_2X12_BE, | ||
| 74 | .bpp = 24, | ||
| 75 | }, { | ||
| 76 | .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ | ||
| 77 | .code = MEDIA_BUS_FMT_ARGB8888_1X32, | ||
| 78 | .bpp = 32, | ||
| 79 | }, { | ||
| 80 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
| 81 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, | ||
| 82 | .bpp = 8, | ||
| 83 | }, { | ||
| 84 | .fourcc = V4L2_PIX_FMT_SGBRG8, | ||
| 85 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, | ||
| 86 | .bpp = 8, | ||
| 87 | }, { | ||
| 88 | .fourcc = V4L2_PIX_FMT_SGRBG8, | ||
| 89 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, | ||
| 90 | .bpp = 8, | ||
| 91 | }, { | ||
| 92 | .fourcc = V4L2_PIX_FMT_SRGGB8, | ||
| 93 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, | ||
| 94 | .bpp = 8, | ||
| 95 | }, { | ||
| 96 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
| 97 | .code = MEDIA_BUS_FMT_SBGGR10_1X10, | ||
| 98 | .bpp = 10, | ||
| 99 | }, { | ||
| 100 | .fourcc = V4L2_PIX_FMT_SGBRG10, | ||
| 101 | .code = MEDIA_BUS_FMT_SGBRG10_1X10, | ||
| 102 | .bpp = 10, | ||
| 103 | }, { | ||
| 104 | .fourcc = V4L2_PIX_FMT_SGRBG10, | ||
| 105 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, | ||
| 106 | .bpp = 10, | ||
| 107 | }, { | ||
| 108 | .fourcc = V4L2_PIX_FMT_SRGGB10, | ||
| 109 | .code = MEDIA_BUS_FMT_SRGGB10_1X10, | ||
| 110 | .bpp = 10, | ||
| 111 | }, { | ||
| 112 | .fourcc = V4L2_PIX_FMT_SBGGR12, | ||
| 113 | .code = MEDIA_BUS_FMT_SBGGR12_1X12, | ||
| 114 | .bpp = 12, | ||
| 115 | }, { | ||
| 116 | .fourcc = V4L2_PIX_FMT_SGBRG12, | ||
| 117 | .code = MEDIA_BUS_FMT_SGBRG12_1X12, | ||
| 118 | .bpp = 12, | ||
| 119 | }, { | ||
| 120 | .fourcc = V4L2_PIX_FMT_SGRBG12, | ||
| 121 | .code = MEDIA_BUS_FMT_SGRBG12_1X12, | ||
| 122 | .bpp = 12, | ||
| 123 | }, { | ||
| 124 | .fourcc = V4L2_PIX_FMT_SRGGB12, | ||
| 125 | .code = MEDIA_BUS_FMT_SRGGB12_1X12, | ||
| 126 | .bpp = 12, | ||
| 127 | }, | ||
| 128 | }; | ||
| 129 | |||
| 130 | /* Print Four-character-code (FOURCC) */ | ||
| 131 | static char *fourcc_to_str(u32 fmt) | ||
| 132 | { | ||
| 133 | static char code[5]; | ||
| 134 | |||
| 135 | code[0] = (unsigned char)(fmt & 0xff); | ||
| 136 | code[1] = (unsigned char)((fmt >> 8) & 0xff); | ||
| 137 | code[2] = (unsigned char)((fmt >> 16) & 0xff); | ||
| 138 | code[3] = (unsigned char)((fmt >> 24) & 0xff); | ||
| 139 | code[4] = '\0'; | ||
| 140 | |||
| 141 | return code; | ||
| 142 | } | ||
| 143 | |||
| 144 | /* ------------------------------------------------------------------ | ||
| 145 | * V4L2 Video IOCTLs | ||
| 146 | * ------------------------------------------------------------------ | ||
| 147 | */ | ||
| 148 | |||
| 149 | static const struct cal_fmt *find_format_by_pix(struct cal_ctx *ctx, | ||
| 150 | u32 pixelformat) | ||
| 151 | { | ||
| 152 | const struct cal_fmt *fmt; | ||
| 153 | unsigned int k; | ||
| 154 | |||
| 155 | for (k = 0; k < ctx->num_active_fmt; k++) { | ||
| 156 | fmt = ctx->active_fmt[k]; | ||
| 157 | if (fmt->fourcc == pixelformat) | ||
| 158 | return fmt; | ||
| 159 | } | ||
| 160 | |||
| 161 | return NULL; | ||
| 162 | } | ||
| 163 | |||
| 164 | static const struct cal_fmt *find_format_by_code(struct cal_ctx *ctx, | ||
| 165 | u32 code) | ||
| 166 | { | ||
| 167 | const struct cal_fmt *fmt; | ||
| 168 | unsigned int k; | ||
| 169 | |||
| 170 | for (k = 0; k < ctx->num_active_fmt; k++) { | ||
| 171 | fmt = ctx->active_fmt[k]; | ||
| 172 | if (fmt->code == code) | ||
| 173 | return fmt; | ||
| 174 | } | ||
| 175 | |||
| 176 | return NULL; | ||
| 177 | } | ||
| 178 | |||
| 179 | static int cal_querycap(struct file *file, void *priv, | ||
| 180 | struct v4l2_capability *cap) | ||
| 181 | { | ||
| 182 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 183 | |||
| 184 | strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); | ||
| 185 | strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); | ||
| 186 | |||
| 187 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ||
| 188 | "platform:%s", dev_name(ctx->cal->dev)); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | static int cal_enum_fmt_vid_cap(struct file *file, void *priv, | ||
| 193 | struct v4l2_fmtdesc *f) | ||
| 194 | { | ||
| 195 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 196 | const struct cal_fmt *fmt; | ||
| 197 | |||
| 198 | if (f->index >= ctx->num_active_fmt) | ||
| 199 | return -EINVAL; | ||
| 200 | |||
| 201 | fmt = ctx->active_fmt[f->index]; | ||
| 202 | |||
| 203 | f->pixelformat = fmt->fourcc; | ||
| 204 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int __subdev_get_format(struct cal_ctx *ctx, | ||
| 209 | struct v4l2_mbus_framefmt *fmt) | ||
| 210 | { | ||
| 211 | struct v4l2_subdev_format sd_fmt; | ||
| 212 | struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; | ||
| 213 | int ret; | ||
| 214 | |||
| 215 | sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 216 | sd_fmt.pad = 0; | ||
| 217 | |||
| 218 | ret = v4l2_subdev_call(ctx->phy->sensor, pad, get_fmt, NULL, &sd_fmt); | ||
| 219 | if (ret) | ||
| 220 | return ret; | ||
| 221 | |||
| 222 | *fmt = *mbus_fmt; | ||
| 223 | |||
| 224 | ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, | ||
| 225 | fmt->width, fmt->height, fmt->code); | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | static int __subdev_set_format(struct cal_ctx *ctx, | ||
| 231 | struct v4l2_mbus_framefmt *fmt) | ||
| 232 | { | ||
| 233 | struct v4l2_subdev_format sd_fmt; | ||
| 234 | struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; | ||
| 235 | int ret; | ||
| 236 | |||
| 237 | sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 238 | sd_fmt.pad = 0; | ||
| 239 | *mbus_fmt = *fmt; | ||
| 240 | |||
| 241 | ret = v4l2_subdev_call(ctx->phy->sensor, pad, set_fmt, NULL, &sd_fmt); | ||
| 242 | if (ret) | ||
| 243 | return ret; | ||
| 244 | |||
| 245 | ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, | ||
| 246 | fmt->width, fmt->height, fmt->code); | ||
| 247 | |||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int cal_calc_format_size(struct cal_ctx *ctx, | ||
| 252 | const struct cal_fmt *fmt, | ||
| 253 | struct v4l2_format *f) | ||
| 254 | { | ||
| 255 | u32 bpl, max_width; | ||
| 256 | |||
| 257 | if (!fmt) { | ||
| 258 | ctx_dbg(3, ctx, "No cal_fmt provided!\n"); | ||
| 259 | return -EINVAL; | ||
| 260 | } | ||
| 261 | |||
| 262 | /* | ||
| 263 | * Maximum width is bound by the DMA max width in bytes. | ||
| 264 | * We need to recalculate the actual maxi width depending on the | ||
| 265 | * number of bytes per pixels required. | ||
| 266 | */ | ||
| 267 | max_width = MAX_WIDTH_BYTES / (ALIGN(fmt->bpp, 8) >> 3); | ||
| 268 | v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2, | ||
| 269 | &f->fmt.pix.height, 32, MAX_HEIGHT_LINES, 0, 0); | ||
| 270 | |||
| 271 | bpl = (f->fmt.pix.width * ALIGN(fmt->bpp, 8)) >> 3; | ||
| 272 | f->fmt.pix.bytesperline = ALIGN(bpl, 16); | ||
| 273 | |||
| 274 | f->fmt.pix.sizeimage = f->fmt.pix.height * | ||
| 275 | f->fmt.pix.bytesperline; | ||
| 276 | |||
| 277 | ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n", | ||
| 278 | __func__, fourcc_to_str(f->fmt.pix.pixelformat), | ||
| 279 | f->fmt.pix.width, f->fmt.pix.height, | ||
| 280 | f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); | ||
| 281 | |||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int cal_g_fmt_vid_cap(struct file *file, void *priv, | ||
| 286 | struct v4l2_format *f) | ||
| 287 | { | ||
| 288 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 289 | |||
| 290 | *f = ctx->v_fmt; | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | static int cal_try_fmt_vid_cap(struct file *file, void *priv, | ||
| 296 | struct v4l2_format *f) | ||
| 297 | { | ||
| 298 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 299 | const struct cal_fmt *fmt; | ||
| 300 | struct v4l2_subdev_frame_size_enum fse; | ||
| 301 | int ret, found; | ||
| 302 | |||
| 303 | fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat); | ||
| 304 | if (!fmt) { | ||
| 305 | ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n", | ||
| 306 | f->fmt.pix.pixelformat); | ||
| 307 | |||
| 308 | /* Just get the first one enumerated */ | ||
| 309 | fmt = ctx->active_fmt[0]; | ||
| 310 | f->fmt.pix.pixelformat = fmt->fourcc; | ||
| 311 | } | ||
| 312 | |||
| 313 | f->fmt.pix.field = ctx->v_fmt.fmt.pix.field; | ||
| 314 | |||
| 315 | /* check for/find a valid width/height */ | ||
| 316 | ret = 0; | ||
| 317 | found = false; | ||
| 318 | fse.pad = 0; | ||
| 319 | fse.code = fmt->code; | ||
| 320 | fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 321 | for (fse.index = 0; ; fse.index++) { | ||
| 322 | ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, | ||
| 323 | NULL, &fse); | ||
| 324 | if (ret) | ||
| 325 | break; | ||
| 326 | |||
| 327 | if ((f->fmt.pix.width == fse.max_width) && | ||
| 328 | (f->fmt.pix.height == fse.max_height)) { | ||
| 329 | found = true; | ||
| 330 | break; | ||
| 331 | } else if ((f->fmt.pix.width >= fse.min_width) && | ||
| 332 | (f->fmt.pix.width <= fse.max_width) && | ||
| 333 | (f->fmt.pix.height >= fse.min_height) && | ||
| 334 | (f->fmt.pix.height <= fse.max_height)) { | ||
| 335 | found = true; | ||
| 336 | break; | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | if (!found) { | ||
| 341 | /* use existing values as default */ | ||
| 342 | f->fmt.pix.width = ctx->v_fmt.fmt.pix.width; | ||
| 343 | f->fmt.pix.height = ctx->v_fmt.fmt.pix.height; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* | ||
| 347 | * Use current colorspace for now, it will get | ||
| 348 | * updated properly during s_fmt | ||
| 349 | */ | ||
| 350 | f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace; | ||
| 351 | return cal_calc_format_size(ctx, fmt, f); | ||
| 352 | } | ||
| 353 | |||
| 354 | static int cal_s_fmt_vid_cap(struct file *file, void *priv, | ||
| 355 | struct v4l2_format *f) | ||
| 356 | { | ||
| 357 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 358 | struct vb2_queue *q = &ctx->vb_vidq; | ||
| 359 | const struct cal_fmt *fmt; | ||
| 360 | struct v4l2_mbus_framefmt mbus_fmt; | ||
| 361 | int ret; | ||
| 362 | |||
| 363 | if (vb2_is_busy(q)) { | ||
| 364 | ctx_dbg(3, ctx, "%s device busy\n", __func__); | ||
| 365 | return -EBUSY; | ||
| 366 | } | ||
| 367 | |||
| 368 | ret = cal_try_fmt_vid_cap(file, priv, f); | ||
| 369 | if (ret < 0) | ||
| 370 | return ret; | ||
| 371 | |||
| 372 | fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat); | ||
| 373 | |||
| 374 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code); | ||
| 375 | |||
| 376 | ret = __subdev_set_format(ctx, &mbus_fmt); | ||
| 377 | if (ret) | ||
| 378 | return ret; | ||
| 379 | |||
| 380 | /* Just double check nothing has gone wrong */ | ||
| 381 | if (mbus_fmt.code != fmt->code) { | ||
| 382 | ctx_dbg(3, ctx, | ||
| 383 | "%s subdev changed format on us, this should not happen\n", | ||
| 384 | __func__); | ||
| 385 | return -EINVAL; | ||
| 386 | } | ||
| 387 | |||
| 388 | v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt); | ||
| 389 | ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 390 | ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc; | ||
| 391 | cal_calc_format_size(ctx, fmt, &ctx->v_fmt); | ||
| 392 | ctx->fmt = fmt; | ||
| 393 | ctx->m_fmt = mbus_fmt; | ||
| 394 | *f = ctx->v_fmt; | ||
| 395 | |||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | static int cal_enum_framesizes(struct file *file, void *fh, | ||
| 400 | struct v4l2_frmsizeenum *fsize) | ||
| 401 | { | ||
| 402 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 403 | const struct cal_fmt *fmt; | ||
| 404 | struct v4l2_subdev_frame_size_enum fse; | ||
| 405 | int ret; | ||
| 406 | |||
| 407 | /* check for valid format */ | ||
| 408 | fmt = find_format_by_pix(ctx, fsize->pixel_format); | ||
| 409 | if (!fmt) { | ||
| 410 | ctx_dbg(3, ctx, "Invalid pixel code: %x\n", | ||
| 411 | fsize->pixel_format); | ||
| 412 | return -EINVAL; | ||
| 413 | } | ||
| 414 | |||
| 415 | fse.index = fsize->index; | ||
| 416 | fse.pad = 0; | ||
| 417 | fse.code = fmt->code; | ||
| 418 | fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 419 | |||
| 420 | ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, NULL, | ||
| 421 | &fse); | ||
| 422 | if (ret) | ||
| 423 | return ret; | ||
| 424 | |||
| 425 | ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", | ||
| 426 | __func__, fse.index, fse.code, fse.min_width, fse.max_width, | ||
| 427 | fse.min_height, fse.max_height); | ||
| 428 | |||
| 429 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
| 430 | fsize->discrete.width = fse.max_width; | ||
| 431 | fsize->discrete.height = fse.max_height; | ||
| 432 | |||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int cal_enum_input(struct file *file, void *priv, | ||
| 437 | struct v4l2_input *inp) | ||
| 438 | { | ||
| 439 | if (inp->index > 0) | ||
| 440 | return -EINVAL; | ||
| 441 | |||
| 442 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
| 443 | sprintf(inp->name, "Camera %u", inp->index); | ||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | |||
| 447 | static int cal_g_input(struct file *file, void *priv, unsigned int *i) | ||
| 448 | { | ||
| 449 | *i = 0; | ||
| 450 | return 0; | ||
| 451 | } | ||
| 452 | |||
| 453 | static int cal_s_input(struct file *file, void *priv, unsigned int i) | ||
| 454 | { | ||
| 455 | return i > 0 ? -EINVAL : 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* timeperframe is arbitrary and continuous */ | ||
| 459 | static int cal_enum_frameintervals(struct file *file, void *priv, | ||
| 460 | struct v4l2_frmivalenum *fival) | ||
| 461 | { | ||
| 462 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 463 | const struct cal_fmt *fmt; | ||
| 464 | struct v4l2_subdev_frame_interval_enum fie = { | ||
| 465 | .index = fival->index, | ||
| 466 | .width = fival->width, | ||
| 467 | .height = fival->height, | ||
| 468 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
| 469 | }; | ||
| 470 | int ret; | ||
| 471 | |||
| 472 | fmt = find_format_by_pix(ctx, fival->pixel_format); | ||
| 473 | if (!fmt) | ||
| 474 | return -EINVAL; | ||
| 475 | |||
| 476 | fie.code = fmt->code; | ||
| 477 | ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_interval, | ||
| 478 | NULL, &fie); | ||
| 479 | if (ret) | ||
| 480 | return ret; | ||
| 481 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
| 482 | fival->discrete = fie.interval; | ||
| 483 | |||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | static const struct v4l2_file_operations cal_fops = { | ||
| 488 | .owner = THIS_MODULE, | ||
| 489 | .open = v4l2_fh_open, | ||
| 490 | .release = vb2_fop_release, | ||
| 491 | .read = vb2_fop_read, | ||
| 492 | .poll = vb2_fop_poll, | ||
| 493 | .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ | ||
| 494 | .mmap = vb2_fop_mmap, | ||
| 495 | }; | ||
| 496 | |||
| 497 | static const struct v4l2_ioctl_ops cal_ioctl_ops = { | ||
| 498 | .vidioc_querycap = cal_querycap, | ||
| 499 | .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap, | ||
| 500 | .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, | ||
| 501 | .vidioc_try_fmt_vid_cap = cal_try_fmt_vid_cap, | ||
| 502 | .vidioc_s_fmt_vid_cap = cal_s_fmt_vid_cap, | ||
| 503 | .vidioc_enum_framesizes = cal_enum_framesizes, | ||
| 504 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
| 505 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
| 506 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
| 507 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
| 508 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
| 509 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
| 510 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
| 511 | .vidioc_enum_input = cal_enum_input, | ||
| 512 | .vidioc_g_input = cal_g_input, | ||
| 513 | .vidioc_s_input = cal_s_input, | ||
| 514 | .vidioc_enum_frameintervals = cal_enum_frameintervals, | ||
| 515 | .vidioc_streamon = vb2_ioctl_streamon, | ||
| 516 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
| 517 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
| 518 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
| 519 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
| 520 | }; | ||
| 521 | |||
| 522 | /* ------------------------------------------------------------------ | ||
| 523 | * videobuf2 Operations | ||
| 524 | * ------------------------------------------------------------------ | ||
| 525 | */ | ||
| 526 | |||
| 527 | static int cal_queue_setup(struct vb2_queue *vq, | ||
| 528 | unsigned int *nbuffers, unsigned int *nplanes, | ||
| 529 | unsigned int sizes[], struct device *alloc_devs[]) | ||
| 530 | { | ||
| 531 | struct cal_ctx *ctx = vb2_get_drv_priv(vq); | ||
| 532 | unsigned int size = ctx->v_fmt.fmt.pix.sizeimage; | ||
| 533 | |||
| 534 | if (vq->num_buffers + *nbuffers < 3) | ||
| 535 | *nbuffers = 3 - vq->num_buffers; | ||
| 536 | |||
| 537 | if (*nplanes) { | ||
| 538 | if (sizes[0] < size) | ||
| 539 | return -EINVAL; | ||
| 540 | size = sizes[0]; | ||
| 541 | } | ||
| 542 | |||
| 543 | *nplanes = 1; | ||
| 544 | sizes[0] = size; | ||
| 545 | |||
| 546 | ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]); | ||
| 547 | |||
| 548 | return 0; | ||
| 549 | } | ||
| 550 | |||
| 551 | static int cal_buffer_prepare(struct vb2_buffer *vb) | ||
| 552 | { | ||
| 553 | struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
| 554 | struct cal_buffer *buf = container_of(vb, struct cal_buffer, | ||
| 555 | vb.vb2_buf); | ||
| 556 | unsigned long size; | ||
| 557 | |||
| 558 | if (WARN_ON(!ctx->fmt)) | ||
| 559 | return -EINVAL; | ||
| 560 | |||
| 561 | size = ctx->v_fmt.fmt.pix.sizeimage; | ||
| 562 | if (vb2_plane_size(vb, 0) < size) { | ||
| 563 | ctx_err(ctx, | ||
| 564 | "data will not fit into plane (%lu < %lu)\n", | ||
| 565 | vb2_plane_size(vb, 0), size); | ||
| 566 | return -EINVAL; | ||
| 567 | } | ||
| 568 | |||
| 569 | vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); | ||
| 570 | return 0; | ||
| 571 | } | ||
| 572 | |||
| 573 | static void cal_buffer_queue(struct vb2_buffer *vb) | ||
| 574 | { | ||
| 575 | struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
| 576 | struct cal_buffer *buf = container_of(vb, struct cal_buffer, | ||
| 577 | vb.vb2_buf); | ||
| 578 | struct cal_dmaqueue *vidq = &ctx->vidq; | ||
| 579 | unsigned long flags; | ||
| 580 | |||
| 581 | /* recheck locking */ | ||
| 582 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 583 | list_add_tail(&buf->list, &vidq->active); | ||
| 584 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 585 | } | ||
| 586 | |||
| 587 | static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
| 588 | { | ||
| 589 | struct cal_ctx *ctx = vb2_get_drv_priv(vq); | ||
| 590 | struct cal_dmaqueue *dma_q = &ctx->vidq; | ||
| 591 | struct cal_buffer *buf, *tmp; | ||
| 592 | unsigned long addr; | ||
| 593 | unsigned long flags; | ||
| 594 | int ret; | ||
| 595 | |||
| 596 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 597 | if (list_empty(&dma_q->active)) { | ||
| 598 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 599 | ctx_dbg(3, ctx, "buffer queue is empty\n"); | ||
| 600 | return -EIO; | ||
| 601 | } | ||
| 602 | |||
| 603 | buf = list_entry(dma_q->active.next, struct cal_buffer, list); | ||
| 604 | ctx->cur_frm = buf; | ||
| 605 | ctx->next_frm = buf; | ||
| 606 | list_del(&buf->list); | ||
| 607 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 608 | |||
| 609 | addr = vb2_dma_contig_plane_dma_addr(&ctx->cur_frm->vb.vb2_buf, 0); | ||
| 610 | ctx->sequence = 0; | ||
| 611 | |||
| 612 | pm_runtime_get_sync(ctx->cal->dev); | ||
| 613 | |||
| 614 | cal_ctx_csi2_config(ctx); | ||
| 615 | cal_ctx_pix_proc_config(ctx); | ||
| 616 | cal_ctx_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline, | ||
| 617 | ctx->v_fmt.fmt.pix.height); | ||
| 618 | |||
| 619 | cal_camerarx_enable_irqs(ctx->phy); | ||
| 620 | |||
| 621 | ret = cal_camerarx_start(ctx->phy, ctx->fmt); | ||
| 622 | if (ret) | ||
| 623 | goto err; | ||
| 624 | |||
| 625 | cal_ctx_wr_dma_addr(ctx, addr); | ||
| 626 | cal_camerarx_ppi_enable(ctx->phy); | ||
| 627 | |||
| 628 | if (cal_debug >= 4) | ||
| 629 | cal_quickdump_regs(ctx->cal); | ||
| 630 | |||
| 631 | return 0; | ||
| 632 | |||
| 633 | err: | ||
| 634 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 635 | vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
| 636 | ctx->cur_frm = NULL; | ||
| 637 | ctx->next_frm = NULL; | ||
| 638 | list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { | ||
| 639 | list_del(&buf->list); | ||
| 640 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
| 641 | } | ||
| 642 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 643 | return ret; | ||
| 644 | } | ||
| 645 | |||
| 646 | static void cal_stop_streaming(struct vb2_queue *vq) | ||
| 647 | { | ||
| 648 | struct cal_ctx *ctx = vb2_get_drv_priv(vq); | ||
| 649 | struct cal_dmaqueue *dma_q = &ctx->vidq; | ||
| 650 | struct cal_buffer *buf, *tmp; | ||
| 651 | unsigned long timeout; | ||
| 652 | unsigned long flags; | ||
| 653 | bool dma_act; | ||
| 654 | |||
| 655 | cal_camerarx_ppi_disable(ctx->phy); | ||
| 656 | |||
| 657 | /* wait for stream and dma to finish */ | ||
| 658 | dma_act = true; | ||
| 659 | timeout = jiffies + msecs_to_jiffies(500); | ||
| 660 | while (dma_act && time_before(jiffies, timeout)) { | ||
| 661 | msleep(50); | ||
| 662 | |||
| 663 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 664 | dma_act = ctx->dma_act; | ||
| 665 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 666 | } | ||
| 667 | |||
| 668 | if (dma_act) | ||
| 669 | ctx_err(ctx, "failed to disable dma cleanly\n"); | ||
| 670 | |||
| 671 | cal_camerarx_disable_irqs(ctx->phy); | ||
| 672 | cal_camerarx_stop(ctx->phy); | ||
| 673 | |||
| 674 | /* Release all active buffers */ | ||
| 675 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 676 | list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { | ||
| 677 | list_del(&buf->list); | ||
| 678 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
| 679 | } | ||
| 680 | |||
| 681 | if (ctx->cur_frm == ctx->next_frm) { | ||
| 682 | vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
| 683 | } else { | ||
| 684 | vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
| 685 | vb2_buffer_done(&ctx->next_frm->vb.vb2_buf, | ||
| 686 | VB2_BUF_STATE_ERROR); | ||
| 687 | } | ||
| 688 | ctx->cur_frm = NULL; | ||
| 689 | ctx->next_frm = NULL; | ||
| 690 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 691 | |||
| 692 | pm_runtime_put_sync(ctx->cal->dev); | ||
| 693 | } | ||
| 694 | |||
| 695 | static const struct vb2_ops cal_video_qops = { | ||
| 696 | .queue_setup = cal_queue_setup, | ||
| 697 | .buf_prepare = cal_buffer_prepare, | ||
| 698 | .buf_queue = cal_buffer_queue, | ||
| 699 | .start_streaming = cal_start_streaming, | ||
| 700 | .stop_streaming = cal_stop_streaming, | ||
| 701 | .wait_prepare = vb2_ops_wait_prepare, | ||
| 702 | .wait_finish = vb2_ops_wait_finish, | ||
| 703 | }; | ||
| 704 | |||
| 705 | /* ------------------------------------------------------------------ | ||
| 706 | * V4L2 Initialization and Registration | ||
| 707 | * ------------------------------------------------------------------ | ||
| 708 | */ | ||
| 709 | |||
| 710 | static const struct video_device cal_videodev = { | ||
| 711 | .name = CAL_MODULE_NAME, | ||
| 712 | .fops = &cal_fops, | ||
| 713 | .ioctl_ops = &cal_ioctl_ops, | ||
| 714 | .minor = -1, | ||
| 715 | .release = video_device_release_empty, | ||
| 716 | .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | ||
| 717 | V4L2_CAP_READWRITE, | ||
| 718 | }; | ||
| 719 | |||
| 720 | static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) | ||
| 721 | { | ||
| 722 | struct v4l2_subdev_mbus_code_enum mbus_code; | ||
| 723 | struct v4l2_mbus_framefmt mbus_fmt; | ||
| 724 | const struct cal_fmt *fmt; | ||
| 725 | unsigned int i, j, k; | ||
| 726 | int ret = 0; | ||
| 727 | |||
| 728 | /* Enumerate sub device formats and enable all matching local formats */ | ||
| 729 | ctx->active_fmt = devm_kcalloc(ctx->cal->dev, ARRAY_SIZE(cal_formats), | ||
| 730 | sizeof(*ctx->active_fmt), GFP_KERNEL); | ||
| 731 | ctx->num_active_fmt = 0; | ||
| 732 | |||
| 733 | for (j = 0, i = 0; ret != -EINVAL; ++j) { | ||
| 734 | |||
| 735 | memset(&mbus_code, 0, sizeof(mbus_code)); | ||
| 736 | mbus_code.index = j; | ||
| 737 | mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 738 | ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_mbus_code, | ||
| 739 | NULL, &mbus_code); | ||
| 740 | if (ret) | ||
| 741 | continue; | ||
| 742 | |||
| 743 | ctx_dbg(2, ctx, | ||
| 744 | "subdev %s: code: %04x idx: %u\n", | ||
| 745 | ctx->phy->sensor->name, mbus_code.code, j); | ||
| 746 | |||
| 747 | for (k = 0; k < ARRAY_SIZE(cal_formats); k++) { | ||
| 748 | const struct cal_fmt *fmt = &cal_formats[k]; | ||
| 749 | |||
| 750 | if (mbus_code.code == fmt->code) { | ||
| 751 | ctx->active_fmt[i] = fmt; | ||
| 752 | ctx_dbg(2, ctx, | ||
| 753 | "matched fourcc: %s: code: %04x idx: %u\n", | ||
| 754 | fourcc_to_str(fmt->fourcc), | ||
| 755 | fmt->code, i); | ||
| 756 | ctx->num_active_fmt = ++i; | ||
| 757 | } | ||
| 758 | } | ||
| 759 | } | ||
| 760 | |||
| 761 | if (i == 0) { | ||
| 762 | ctx_err(ctx, "No suitable format reported by subdev %s\n", | ||
| 763 | ctx->phy->sensor->name); | ||
| 764 | return -EINVAL; | ||
| 765 | } | ||
| 766 | |||
| 767 | ret = __subdev_get_format(ctx, &mbus_fmt); | ||
| 768 | if (ret) | ||
| 769 | return ret; | ||
| 770 | |||
| 771 | fmt = find_format_by_code(ctx, mbus_fmt.code); | ||
| 772 | if (!fmt) { | ||
| 773 | ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n", | ||
| 774 | mbus_fmt.code); | ||
| 775 | return -EINVAL; | ||
| 776 | } | ||
| 777 | |||
| 778 | /* Save current subdev format */ | ||
| 779 | v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt); | ||
| 780 | ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 781 | ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc; | ||
| 782 | cal_calc_format_size(ctx, fmt, &ctx->v_fmt); | ||
| 783 | ctx->fmt = fmt; | ||
| 784 | ctx->m_fmt = mbus_fmt; | ||
| 785 | |||
| 786 | return 0; | ||
| 787 | } | ||
| 788 | |||
| 789 | int cal_ctx_v4l2_register(struct cal_ctx *ctx) | ||
| 790 | { | ||
| 791 | struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; | ||
| 792 | struct video_device *vfd = &ctx->vdev; | ||
| 793 | int ret; | ||
| 794 | |||
| 795 | ret = cal_ctx_v4l2_init_formats(ctx); | ||
| 796 | if (ret) | ||
| 797 | return ret; | ||
| 798 | |||
| 799 | ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler, NULL, | ||
| 800 | true); | ||
| 801 | if (ret < 0) { | ||
| 802 | ctx_err(ctx, "Failed to add sensor ctrl handler\n"); | ||
| 803 | return ret; | ||
| 804 | } | ||
| 805 | |||
| 806 | ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr); | ||
| 807 | if (ret < 0) { | ||
| 808 | ctx_err(ctx, "Failed to register video device\n"); | ||
| 809 | return ret; | ||
| 810 | } | ||
| 811 | |||
| 812 | ctx_info(ctx, "V4L2 device registered as %s\n", | ||
| 813 | video_device_node_name(vfd)); | ||
| 814 | |||
| 815 | return 0; | ||
| 816 | } | ||
| 817 | |||
| 818 | void cal_ctx_v4l2_unregister(struct cal_ctx *ctx) | ||
| 819 | { | ||
| 820 | ctx_dbg(1, ctx, "unregistering %s\n", | ||
| 821 | video_device_node_name(&ctx->vdev)); | ||
| 822 | |||
| 823 | video_unregister_device(&ctx->vdev); | ||
| 824 | } | ||
| 825 | |||
| 826 | int cal_ctx_v4l2_init(struct cal_ctx *ctx) | ||
| 827 | { | ||
| 828 | struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; | ||
| 829 | struct video_device *vfd = &ctx->vdev; | ||
| 830 | struct vb2_queue *q = &ctx->vb_vidq; | ||
| 831 | int ret; | ||
| 832 | |||
| 833 | INIT_LIST_HEAD(&ctx->vidq.active); | ||
| 834 | spin_lock_init(&ctx->slock); | ||
| 835 | mutex_init(&ctx->mutex); | ||
| 836 | |||
| 837 | /* Initialize the vb2 queue. */ | ||
| 838 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 839 | q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; | ||
| 840 | q->drv_priv = ctx; | ||
| 841 | q->buf_struct_size = sizeof(struct cal_buffer); | ||
| 842 | q->ops = &cal_video_qops; | ||
| 843 | q->mem_ops = &vb2_dma_contig_memops; | ||
| 844 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
| 845 | q->lock = &ctx->mutex; | ||
| 846 | q->min_buffers_needed = 3; | ||
| 847 | q->dev = ctx->cal->dev; | ||
| 848 | |||
| 849 | ret = vb2_queue_init(q); | ||
| 850 | if (ret) | ||
| 851 | return ret; | ||
| 852 | |||
| 853 | /* Initialize the video device and media entity. */ | ||
| 854 | *vfd = cal_videodev; | ||
| 855 | vfd->v4l2_dev = &ctx->cal->v4l2_dev; | ||
| 856 | vfd->queue = q; | ||
| 857 | snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->index); | ||
| 858 | vfd->lock = &ctx->mutex; | ||
| 859 | video_set_drvdata(vfd, ctx); | ||
| 860 | |||
| 861 | ctx->pad.flags = MEDIA_PAD_FL_SINK; | ||
| 862 | ret = media_entity_pads_init(&vfd->entity, 1, &ctx->pad); | ||
| 863 | if (ret < 0) | ||
| 864 | return ret; | ||
| 865 | |||
| 866 | /* Initialize the control handler. */ | ||
| 867 | ret = v4l2_ctrl_handler_init(hdl, 11); | ||
| 868 | if (ret < 0) { | ||
| 869 | ctx_err(ctx, "Failed to init ctrl handler\n"); | ||
| 870 | goto error; | ||
| 871 | } | ||
| 872 | |||
| 873 | vfd->ctrl_handler = hdl; | ||
| 874 | |||
| 875 | return 0; | ||
| 876 | |||
| 877 | error: | ||
| 878 | media_entity_cleanup(&vfd->entity); | ||
| 879 | return ret; | ||
| 880 | } | ||
| 881 | |||
| 882 | void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx) | ||
| 883 | { | ||
| 884 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
| 885 | media_entity_cleanup(&ctx->vdev.entity); | ||
| 886 | } | ||
| @@ -1,976 +1,167 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* | 2 | /* |
| 3 | * TI CAL camera interface driver | 3 | * TI Camera Access Layer (CAL) - Driver |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2015 Texas Instruments Inc. | 5 | * Copyright (c) 2015-2020 Texas Instruments Inc. |
| 6 | * Benoit Parrot, <bparrot@ti.com> | 6 | * |
| 7 | * Authors: | ||
| 8 | * Benoit Parrot <bparrot@ti.com> | ||
| 9 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 7 | */ | 10 | */ |
| 8 | 11 | ||
| 9 | #include <linux/clk.h> | 12 | #include <linux/clk.h> |
| 10 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 11 | #include <linux/io.h> | 14 | #include <linux/mfd/syscon.h> |
| 12 | #include <linux/ioctl.h> | ||
| 13 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/of_device.h> | ||
| 14 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/pm_runtime.h> | 18 | #include <linux/pm_runtime.h> |
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/mfd/syscon.h> | ||
| 19 | #include <linux/regmap.h> | 19 | #include <linux/regmap.h> |
| 20 | #include <linux/slab.h> | ||
| 20 | #include <linux/videodev2.h> | 21 | #include <linux/videodev2.h> |
| 21 | #include <linux/of_device.h> | ||
| 22 | #include <linux/of_graph.h> | ||
| 23 | 22 | ||
| 24 | #include <media/v4l2-fwnode.h> | 23 | #include <media/media-device.h> |
| 25 | #include <media/v4l2-async.h> | 24 | #include <media/v4l2-async.h> |
| 26 | #include <media/v4l2-common.h> | 25 | #include <media/v4l2-common.h> |
| 27 | #include <media/v4l2-ctrls.h> | ||
| 28 | #include <media/v4l2-device.h> | 26 | #include <media/v4l2-device.h> |
| 29 | #include <media/v4l2-event.h> | ||
| 30 | #include <media/v4l2-ioctl.h> | ||
| 31 | #include <media/v4l2-fh.h> | ||
| 32 | #include <media/videobuf2-core.h> | 27 | #include <media/videobuf2-core.h> |
| 33 | #include <media/videobuf2-dma-contig.h> | 28 | #include <media/videobuf2-dma-contig.h> |
| 34 | #include "cal_regs.h" | ||
| 35 | 29 | ||
| 36 | #define CAL_MODULE_NAME "cal" | 30 | #include "cal.h" |
| 37 | 31 | #include "cal_regs.h" | |
| 38 | #define MAX_WIDTH_BYTES (8192 * 8) | ||
| 39 | #define MAX_HEIGHT_LINES 16383 | ||
| 40 | |||
| 41 | #define CAL_VERSION "0.1.0" | ||
| 42 | 32 | ||
| 43 | MODULE_DESCRIPTION("TI CAL driver"); | 33 | MODULE_DESCRIPTION("TI CAL driver"); |
| 44 | MODULE_AUTHOR("Benoit Parrot, <bparrot@ti.com>"); | 34 | MODULE_AUTHOR("Benoit Parrot, <bparrot@ti.com>"); |
| 45 | MODULE_LICENSE("GPL v2"); | 35 | MODULE_LICENSE("GPL v2"); |
| 46 | MODULE_VERSION(CAL_VERSION); | 36 | MODULE_VERSION("0.1.0"); |
| 47 | 37 | ||
| 48 | static unsigned video_nr = -1; | 38 | int cal_video_nr = -1; |
| 49 | module_param(video_nr, uint, 0644); | 39 | module_param_named(video_nr, cal_video_nr, uint, 0644); |
| 50 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); | 40 | MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); |
| 51 | 41 | ||
| 52 | static unsigned debug; | 42 | unsigned int cal_debug; |
| 53 | module_param(debug, uint, 0644); | 43 | module_param_named(debug, cal_debug, uint, 0644); |
| 54 | MODULE_PARM_DESC(debug, "activates debug info"); | 44 | MODULE_PARM_DESC(debug, "activates debug info"); |
| 55 | 45 | ||
| 56 | /* timeperframe: min/max and default */ | ||
| 57 | static const struct v4l2_fract | ||
| 58 | tpf_default = {.numerator = 1001, .denominator = 30000}; | ||
| 59 | |||
| 60 | #define cal_dbg(level, caldev, fmt, arg...) \ | ||
| 61 | v4l2_dbg(level, debug, &caldev->v4l2_dev, fmt, ##arg) | ||
| 62 | #define cal_info(caldev, fmt, arg...) \ | ||
| 63 | v4l2_info(&caldev->v4l2_dev, fmt, ##arg) | ||
| 64 | #define cal_err(caldev, fmt, arg...) \ | ||
| 65 | v4l2_err(&caldev->v4l2_dev, fmt, ##arg) | ||
| 66 | |||
| 67 | #define ctx_dbg(level, ctx, fmt, arg...) \ | ||
| 68 | v4l2_dbg(level, debug, &ctx->v4l2_dev, fmt, ##arg) | ||
| 69 | #define ctx_info(ctx, fmt, arg...) \ | ||
| 70 | v4l2_info(&ctx->v4l2_dev, fmt, ##arg) | ||
| 71 | #define ctx_err(ctx, fmt, arg...) \ | ||
| 72 | v4l2_err(&ctx->v4l2_dev, fmt, ##arg) | ||
| 73 | |||
| 74 | #define CAL_NUM_INPUT 1 | ||
| 75 | #define CAL_NUM_CONTEXT 2 | ||
| 76 | |||
| 77 | #define reg_read(dev, offset) ioread32(dev->base + offset) | ||
| 78 | #define reg_write(dev, offset, val) iowrite32(val, dev->base + offset) | ||
| 79 | |||
| 80 | #define reg_read_field(dev, offset, mask) get_field(reg_read(dev, offset), \ | ||
| 81 | mask) | ||
| 82 | #define reg_write_field(dev, offset, field, mask) { \ | ||
| 83 | u32 val = reg_read(dev, offset); \ | ||
| 84 | set_field(&val, field, mask); \ | ||
| 85 | reg_write(dev, offset, val); } | ||
| 86 | |||
| 87 | /* ------------------------------------------------------------------ | 46 | /* ------------------------------------------------------------------ |
| 88 | * Basic structures | 47 | * Platform Data |
| 89 | * ------------------------------------------------------------------ | 48 | * ------------------------------------------------------------------ |
| 90 | */ | 49 | */ |
| 91 | 50 | ||
| 92 | struct cal_fmt { | 51 | static const struct cal_camerarx_data dra72x_cal_camerarx[] = { |
| 93 | u32 fourcc; | ||
| 94 | u32 code; | ||
| 95 | /* Bits per pixel */ | ||
| 96 | u8 bpp; | ||
| 97 | }; | ||
| 98 | |||
| 99 | static struct cal_fmt cal_formats[] = { | ||
| 100 | { | ||
| 101 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
| 102 | .code = MEDIA_BUS_FMT_YUYV8_2X8, | ||
| 103 | .bpp = 16, | ||
| 104 | }, { | ||
| 105 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
| 106 | .code = MEDIA_BUS_FMT_UYVY8_2X8, | ||
| 107 | .bpp = 16, | ||
| 108 | }, { | ||
| 109 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
| 110 | .code = MEDIA_BUS_FMT_YVYU8_2X8, | ||
| 111 | .bpp = 16, | ||
| 112 | }, { | ||
| 113 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
| 114 | .code = MEDIA_BUS_FMT_VYUY8_2X8, | ||
| 115 | .bpp = 16, | ||
| 116 | }, { | ||
| 117 | .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ | ||
| 118 | .code = MEDIA_BUS_FMT_RGB565_2X8_LE, | ||
| 119 | .bpp = 16, | ||
| 120 | }, { | ||
| 121 | .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ | ||
| 122 | .code = MEDIA_BUS_FMT_RGB565_2X8_BE, | ||
| 123 | .bpp = 16, | ||
| 124 | }, { | ||
| 125 | .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ | ||
| 126 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, | ||
| 127 | .bpp = 16, | ||
| 128 | }, { | ||
| 129 | .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ | ||
| 130 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, | ||
| 131 | .bpp = 16, | ||
| 132 | }, { | ||
| 133 | .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ | ||
| 134 | .code = MEDIA_BUS_FMT_RGB888_2X12_LE, | ||
| 135 | .bpp = 24, | ||
| 136 | }, { | ||
| 137 | .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ | ||
| 138 | .code = MEDIA_BUS_FMT_RGB888_2X12_BE, | ||
| 139 | .bpp = 24, | ||
| 140 | }, { | ||
| 141 | .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ | ||
| 142 | .code = MEDIA_BUS_FMT_ARGB8888_1X32, | ||
| 143 | .bpp = 32, | ||
| 144 | }, { | ||
| 145 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
| 146 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, | ||
| 147 | .bpp = 8, | ||
| 148 | }, { | ||
| 149 | .fourcc = V4L2_PIX_FMT_SGBRG8, | ||
| 150 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, | ||
| 151 | .bpp = 8, | ||
| 152 | }, { | ||
| 153 | .fourcc = V4L2_PIX_FMT_SGRBG8, | ||
| 154 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, | ||
| 155 | .bpp = 8, | ||
| 156 | }, { | ||
| 157 | .fourcc = V4L2_PIX_FMT_SRGGB8, | ||
| 158 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, | ||
| 159 | .bpp = 8, | ||
| 160 | }, { | ||
| 161 | .fourcc = V4L2_PIX_FMT_SBGGR10, | ||
| 162 | .code = MEDIA_BUS_FMT_SBGGR10_1X10, | ||
| 163 | .bpp = 10, | ||
| 164 | }, { | ||
| 165 | .fourcc = V4L2_PIX_FMT_SGBRG10, | ||
| 166 | .code = MEDIA_BUS_FMT_SGBRG10_1X10, | ||
| 167 | .bpp = 10, | ||
| 168 | }, { | ||
| 169 | .fourcc = V4L2_PIX_FMT_SGRBG10, | ||
| 170 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, | ||
| 171 | .bpp = 10, | ||
| 172 | }, { | ||
| 173 | .fourcc = V4L2_PIX_FMT_SRGGB10, | ||
| 174 | .code = MEDIA_BUS_FMT_SRGGB10_1X10, | ||
| 175 | .bpp = 10, | ||
| 176 | }, { | ||
| 177 | .fourcc = V4L2_PIX_FMT_SBGGR12, | ||
| 178 | .code = MEDIA_BUS_FMT_SBGGR12_1X12, | ||
| 179 | .bpp = 12, | ||
| 180 | }, { | ||
| 181 | .fourcc = V4L2_PIX_FMT_SGBRG12, | ||
| 182 | .code = MEDIA_BUS_FMT_SGBRG12_1X12, | ||
| 183 | .bpp = 12, | ||
| 184 | }, { | ||
| 185 | .fourcc = V4L2_PIX_FMT_SGRBG12, | ||
| 186 | .code = MEDIA_BUS_FMT_SGRBG12_1X12, | ||
| 187 | .bpp = 12, | ||
| 188 | }, { | ||
| 189 | .fourcc = V4L2_PIX_FMT_SRGGB12, | ||
| 190 | .code = MEDIA_BUS_FMT_SRGGB12_1X12, | ||
| 191 | .bpp = 12, | ||
| 192 | }, | ||
| 193 | }; | ||
| 194 | |||
| 195 | /* Print Four-character-code (FOURCC) */ | ||
| 196 | static char *fourcc_to_str(u32 fmt) | ||
| 197 | { | ||
| 198 | static char code[5]; | ||
| 199 | |||
| 200 | code[0] = (unsigned char)(fmt & 0xff); | ||
| 201 | code[1] = (unsigned char)((fmt >> 8) & 0xff); | ||
| 202 | code[2] = (unsigned char)((fmt >> 16) & 0xff); | ||
| 203 | code[3] = (unsigned char)((fmt >> 24) & 0xff); | ||
| 204 | code[4] = '\0'; | ||
| 205 | |||
| 206 | return code; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* buffer for one video frame */ | ||
| 210 | struct cal_buffer { | ||
| 211 | /* common v4l buffer stuff -- must be first */ | ||
| 212 | struct vb2_v4l2_buffer vb; | ||
| 213 | struct list_head list; | ||
| 214 | const struct cal_fmt *fmt; | ||
| 215 | }; | ||
| 216 | |||
| 217 | struct cal_dmaqueue { | ||
| 218 | struct list_head active; | ||
| 219 | |||
| 220 | /* Counters to control fps rate */ | ||
| 221 | int frame; | ||
| 222 | int ini_jiffies; | ||
| 223 | }; | ||
| 224 | |||
| 225 | struct cc_data { | ||
| 226 | void __iomem *base; | ||
| 227 | struct resource *res; | ||
| 228 | |||
| 229 | struct platform_device *pdev; | ||
| 230 | }; | ||
| 231 | |||
| 232 | /* CTRL_CORE_CAMERRX_CONTROL register field id */ | ||
| 233 | enum cal_camerarx_field { | ||
| 234 | F_CTRLCLKEN, | ||
| 235 | F_CAMMODE, | ||
| 236 | F_LANEENABLE, | ||
| 237 | F_CSI_MODE, | ||
| 238 | |||
| 239 | F_MAX_FIELDS, | ||
| 240 | }; | ||
| 241 | |||
| 242 | struct cal_csi2_phy { | ||
| 243 | struct regmap_field *fields[F_MAX_FIELDS]; | ||
| 244 | struct reg_field *base_fields; | ||
| 245 | const int num_lanes; | ||
| 246 | }; | ||
| 247 | |||
| 248 | struct cal_data { | ||
| 249 | const int num_csi2_phy; | ||
| 250 | struct cal_csi2_phy *csi2_phy_core; | ||
| 251 | |||
| 252 | const unsigned int flags; | ||
| 253 | }; | ||
| 254 | |||
| 255 | static struct reg_field dra72x_ctrl_core_csi0_reg_fields[F_MAX_FIELDS] = { | ||
| 256 | [F_CTRLCLKEN] = REG_FIELD(0, 10, 10), | ||
| 257 | [F_CAMMODE] = REG_FIELD(0, 11, 12), | ||
| 258 | [F_LANEENABLE] = REG_FIELD(0, 13, 16), | ||
| 259 | [F_CSI_MODE] = REG_FIELD(0, 17, 17), | ||
| 260 | }; | ||
| 261 | |||
| 262 | static struct reg_field dra72x_ctrl_core_csi1_reg_fields[F_MAX_FIELDS] = { | ||
| 263 | [F_CTRLCLKEN] = REG_FIELD(0, 0, 0), | ||
| 264 | [F_CAMMODE] = REG_FIELD(0, 1, 2), | ||
| 265 | [F_LANEENABLE] = REG_FIELD(0, 3, 4), | ||
| 266 | [F_CSI_MODE] = REG_FIELD(0, 5, 5), | ||
| 267 | }; | ||
| 268 | |||
| 269 | static struct cal_csi2_phy dra72x_cal_csi_phy[] = { | ||
| 270 | { | 52 | { |
| 271 | .base_fields = dra72x_ctrl_core_csi0_reg_fields, | 53 | .fields = { |
| 54 | [F_CTRLCLKEN] = { 10, 10 }, | ||
| 55 | [F_CAMMODE] = { 11, 12 }, | ||
| 56 | [F_LANEENABLE] = { 13, 16 }, | ||
| 57 | [F_CSI_MODE] = { 17, 17 }, | ||
| 58 | }, | ||
| 272 | .num_lanes = 4, | 59 | .num_lanes = 4, |
| 273 | }, | 60 | }, |
| 274 | { | 61 | { |
| 275 | .base_fields = dra72x_ctrl_core_csi1_reg_fields, | 62 | .fields = { |
| 63 | [F_CTRLCLKEN] = { 0, 0 }, | ||
| 64 | [F_CAMMODE] = { 1, 2 }, | ||
| 65 | [F_LANEENABLE] = { 3, 4 }, | ||
| 66 | [F_CSI_MODE] = { 5, 5 }, | ||
| 67 | }, | ||
| 276 | .num_lanes = 2, | 68 | .num_lanes = 2, |
| 277 | }, | 69 | }, |
| 278 | }; | 70 | }; |
| 279 | 71 | ||
| 280 | static const struct cal_data dra72x_cal_data = { | 72 | static const struct cal_data dra72x_cal_data = { |
| 281 | .csi2_phy_core = dra72x_cal_csi_phy, | 73 | .camerarx = dra72x_cal_camerarx, |
| 282 | .num_csi2_phy = ARRAY_SIZE(dra72x_cal_csi_phy), | 74 | .num_csi2_phy = ARRAY_SIZE(dra72x_cal_camerarx), |
| 283 | }; | 75 | }; |
| 284 | 76 | ||
| 285 | static const struct cal_data dra72x_es1_cal_data = { | 77 | static const struct cal_data dra72x_es1_cal_data = { |
| 286 | .csi2_phy_core = dra72x_cal_csi_phy, | 78 | .camerarx = dra72x_cal_camerarx, |
| 287 | .num_csi2_phy = ARRAY_SIZE(dra72x_cal_csi_phy), | 79 | .num_csi2_phy = ARRAY_SIZE(dra72x_cal_camerarx), |
| 288 | .flags = DRA72_CAL_PRE_ES2_LDO_DISABLE, | 80 | .flags = DRA72_CAL_PRE_ES2_LDO_DISABLE, |
| 289 | }; | 81 | }; |
| 290 | 82 | ||
| 291 | static struct reg_field dra76x_ctrl_core_csi0_reg_fields[F_MAX_FIELDS] = { | 83 | static const struct cal_camerarx_data dra76x_cal_csi_phy[] = { |
| 292 | [F_CTRLCLKEN] = REG_FIELD(0, 8, 8), | ||
| 293 | [F_CAMMODE] = REG_FIELD(0, 9, 10), | ||
| 294 | [F_CSI_MODE] = REG_FIELD(0, 11, 11), | ||
| 295 | [F_LANEENABLE] = REG_FIELD(0, 27, 31), | ||
| 296 | }; | ||
| 297 | |||
| 298 | static struct reg_field dra76x_ctrl_core_csi1_reg_fields[F_MAX_FIELDS] = { | ||
| 299 | [F_CTRLCLKEN] = REG_FIELD(0, 0, 0), | ||
| 300 | [F_CAMMODE] = REG_FIELD(0, 1, 2), | ||
| 301 | [F_CSI_MODE] = REG_FIELD(0, 3, 3), | ||
| 302 | [F_LANEENABLE] = REG_FIELD(0, 24, 26), | ||
| 303 | }; | ||
| 304 | |||
| 305 | static struct cal_csi2_phy dra76x_cal_csi_phy[] = { | ||
| 306 | { | 84 | { |
| 307 | .base_fields = dra76x_ctrl_core_csi0_reg_fields, | 85 | .fields = { |
| 86 | [F_CTRLCLKEN] = { 8, 8 }, | ||
| 87 | [F_CAMMODE] = { 9, 10 }, | ||
| 88 | [F_CSI_MODE] = { 11, 11 }, | ||
| 89 | [F_LANEENABLE] = { 27, 31 }, | ||
| 90 | }, | ||
| 308 | .num_lanes = 5, | 91 | .num_lanes = 5, |
| 309 | }, | 92 | }, |
| 310 | { | 93 | { |
| 311 | .base_fields = dra76x_ctrl_core_csi1_reg_fields, | 94 | .fields = { |
| 95 | [F_CTRLCLKEN] = { 0, 0 }, | ||
| 96 | [F_CAMMODE] = { 1, 2 }, | ||
| 97 | [F_CSI_MODE] = { 3, 3 }, | ||
| 98 | [F_LANEENABLE] = { 24, 26 }, | ||
| 99 | }, | ||
| 312 | .num_lanes = 3, | 100 | .num_lanes = 3, |
| 313 | }, | 101 | }, |
| 314 | }; | 102 | }; |
| 315 | 103 | ||
| 316 | static const struct cal_data dra76x_cal_data = { | 104 | static const struct cal_data dra76x_cal_data = { |
| 317 | .csi2_phy_core = dra76x_cal_csi_phy, | 105 | .camerarx = dra76x_cal_csi_phy, |
| 318 | .num_csi2_phy = ARRAY_SIZE(dra76x_cal_csi_phy), | 106 | .num_csi2_phy = ARRAY_SIZE(dra76x_cal_csi_phy), |
| 319 | }; | 107 | }; |
| 320 | 108 | ||
| 321 | static struct reg_field am654_ctrl_core_csi0_reg_fields[F_MAX_FIELDS] = { | 109 | static const struct cal_camerarx_data am654_cal_csi_phy[] = { |
| 322 | [F_CTRLCLKEN] = REG_FIELD(0, 15, 15), | ||
| 323 | [F_CAMMODE] = REG_FIELD(0, 24, 25), | ||
| 324 | [F_LANEENABLE] = REG_FIELD(0, 0, 4), | ||
| 325 | }; | ||
| 326 | |||
| 327 | static struct cal_csi2_phy am654_cal_csi_phy[] = { | ||
| 328 | { | 110 | { |
| 329 | .base_fields = am654_ctrl_core_csi0_reg_fields, | 111 | .fields = { |
| 112 | [F_CTRLCLKEN] = { 15, 15 }, | ||
| 113 | [F_CAMMODE] = { 24, 25 }, | ||
| 114 | [F_LANEENABLE] = { 0, 4 }, | ||
| 115 | }, | ||
| 330 | .num_lanes = 5, | 116 | .num_lanes = 5, |
| 331 | }, | 117 | }, |
| 332 | }; | 118 | }; |
| 333 | 119 | ||
| 334 | static const struct cal_data am654_cal_data = { | 120 | static const struct cal_data am654_cal_data = { |
| 335 | .csi2_phy_core = am654_cal_csi_phy, | 121 | .camerarx = am654_cal_csi_phy, |
| 336 | .num_csi2_phy = ARRAY_SIZE(am654_cal_csi_phy), | 122 | .num_csi2_phy = ARRAY_SIZE(am654_cal_csi_phy), |
| 337 | }; | 123 | }; |
| 338 | 124 | ||
| 339 | /* | 125 | /* ------------------------------------------------------------------ |
| 340 | * there is one cal_dev structure in the driver, it is shared by | 126 | * I/O Register Accessors |
| 341 | * all instances. | 127 | * ------------------------------------------------------------------ |
| 342 | */ | ||
| 343 | struct cal_dev { | ||
| 344 | struct clk *fclk; | ||
| 345 | int irq; | ||
| 346 | void __iomem *base; | ||
| 347 | struct resource *res; | ||
| 348 | struct platform_device *pdev; | ||
| 349 | struct v4l2_device v4l2_dev; | ||
| 350 | |||
| 351 | /* Controller flags for special cases */ | ||
| 352 | unsigned int flags; | ||
| 353 | |||
| 354 | const struct cal_data *data; | ||
| 355 | |||
| 356 | /* Control Module handle */ | ||
| 357 | struct regmap *syscon_camerrx; | ||
| 358 | u32 syscon_camerrx_offset; | ||
| 359 | |||
| 360 | /* Camera Core Module handle */ | ||
| 361 | struct cc_data *cc[CAL_NUM_CSI2_PORTS]; | ||
| 362 | |||
| 363 | struct cal_ctx *ctx[CAL_NUM_CONTEXT]; | ||
| 364 | }; | ||
| 365 | |||
| 366 | /* | ||
| 367 | * There is one cal_ctx structure for each camera core context. | ||
| 368 | */ | ||
| 369 | struct cal_ctx { | ||
| 370 | struct v4l2_device v4l2_dev; | ||
| 371 | struct v4l2_ctrl_handler ctrl_handler; | ||
| 372 | struct video_device vdev; | ||
| 373 | struct v4l2_async_notifier notifier; | ||
| 374 | struct v4l2_subdev *sensor; | ||
| 375 | struct v4l2_fwnode_endpoint endpoint; | ||
| 376 | |||
| 377 | struct v4l2_fh fh; | ||
| 378 | struct cal_dev *dev; | ||
| 379 | struct cc_data *cc; | ||
| 380 | |||
| 381 | /* v4l2_ioctl mutex */ | ||
| 382 | struct mutex mutex; | ||
| 383 | /* v4l2 buffers lock */ | ||
| 384 | spinlock_t slock; | ||
| 385 | |||
| 386 | /* Several counters */ | ||
| 387 | unsigned long jiffies; | ||
| 388 | |||
| 389 | struct cal_dmaqueue vidq; | ||
| 390 | |||
| 391 | /* Input Number */ | ||
| 392 | int input; | ||
| 393 | |||
| 394 | /* video capture */ | ||
| 395 | const struct cal_fmt *fmt; | ||
| 396 | /* Used to store current pixel format */ | ||
| 397 | struct v4l2_format v_fmt; | ||
| 398 | /* Used to store current mbus frame format */ | ||
| 399 | struct v4l2_mbus_framefmt m_fmt; | ||
| 400 | |||
| 401 | /* Current subdev enumerated format */ | ||
| 402 | struct cal_fmt *active_fmt[ARRAY_SIZE(cal_formats)]; | ||
| 403 | int num_active_fmt; | ||
| 404 | |||
| 405 | struct v4l2_fract timeperframe; | ||
| 406 | unsigned int sequence; | ||
| 407 | unsigned int external_rate; | ||
| 408 | struct vb2_queue vb_vidq; | ||
| 409 | unsigned int seq_count; | ||
| 410 | unsigned int csi2_port; | ||
| 411 | unsigned int virtual_channel; | ||
| 412 | |||
| 413 | /* Pointer pointing to current v4l2_buffer */ | ||
| 414 | struct cal_buffer *cur_frm; | ||
| 415 | /* Pointer pointing to next v4l2_buffer */ | ||
| 416 | struct cal_buffer *next_frm; | ||
| 417 | |||
| 418 | bool dma_act; | ||
| 419 | }; | ||
| 420 | |||
| 421 | static const struct cal_fmt *find_format_by_pix(struct cal_ctx *ctx, | ||
| 422 | u32 pixelformat) | ||
| 423 | { | ||
| 424 | const struct cal_fmt *fmt; | ||
| 425 | unsigned int k; | ||
| 426 | |||
| 427 | for (k = 0; k < ctx->num_active_fmt; k++) { | ||
| 428 | fmt = ctx->active_fmt[k]; | ||
| 429 | if (fmt->fourcc == pixelformat) | ||
| 430 | return fmt; | ||
| 431 | } | ||
| 432 | |||
| 433 | return NULL; | ||
| 434 | } | ||
| 435 | |||
| 436 | static const struct cal_fmt *find_format_by_code(struct cal_ctx *ctx, | ||
| 437 | u32 code) | ||
| 438 | { | ||
| 439 | const struct cal_fmt *fmt; | ||
| 440 | unsigned int k; | ||
| 441 | |||
| 442 | for (k = 0; k < ctx->num_active_fmt; k++) { | ||
| 443 | fmt = ctx->active_fmt[k]; | ||
| 444 | if (fmt->code == code) | ||
| 445 | return fmt; | ||
| 446 | } | ||
| 447 | |||
| 448 | return NULL; | ||
| 449 | } | ||
| 450 | |||
| 451 | static inline struct cal_ctx *notifier_to_ctx(struct v4l2_async_notifier *n) | ||
| 452 | { | ||
| 453 | return container_of(n, struct cal_ctx, notifier); | ||
| 454 | } | ||
| 455 | |||
| 456 | static inline int get_field(u32 value, u32 mask) | ||
| 457 | { | ||
| 458 | return (value & mask) >> __ffs(mask); | ||
| 459 | } | ||
| 460 | |||
| 461 | static inline void set_field(u32 *valp, u32 field, u32 mask) | ||
| 462 | { | ||
| 463 | u32 val = *valp; | ||
| 464 | |||
| 465 | val &= ~mask; | ||
| 466 | val |= (field << __ffs(mask)) & mask; | ||
| 467 | *valp = val; | ||
| 468 | } | ||
| 469 | |||
| 470 | static u32 cal_data_get_phy_max_lanes(struct cal_ctx *ctx) | ||
| 471 | { | ||
| 472 | struct cal_dev *dev = ctx->dev; | ||
| 473 | u32 phy_id = ctx->csi2_port - 1; | ||
| 474 | |||
| 475 | return dev->data->csi2_phy_core[phy_id].num_lanes; | ||
| 476 | } | ||
| 477 | |||
| 478 | static u32 cal_data_get_num_csi2_phy(struct cal_dev *dev) | ||
| 479 | { | ||
| 480 | return dev->data->num_csi2_phy; | ||
| 481 | } | ||
| 482 | |||
| 483 | static int cal_camerarx_regmap_init(struct cal_dev *dev) | ||
| 484 | { | ||
| 485 | struct reg_field *field; | ||
| 486 | struct cal_csi2_phy *phy; | ||
| 487 | int i, j; | ||
| 488 | |||
| 489 | if (!dev->data) | ||
| 490 | return -EINVAL; | ||
| 491 | |||
| 492 | for (i = 0; i < cal_data_get_num_csi2_phy(dev); i++) { | ||
| 493 | phy = &dev->data->csi2_phy_core[i]; | ||
| 494 | for (j = 0; j < F_MAX_FIELDS; j++) { | ||
| 495 | field = &phy->base_fields[j]; | ||
| 496 | /* | ||
| 497 | * Here we update the reg offset with the | ||
| 498 | * value found in DT | ||
| 499 | */ | ||
| 500 | field->reg = dev->syscon_camerrx_offset; | ||
| 501 | phy->fields[j] = | ||
| 502 | devm_regmap_field_alloc(&dev->pdev->dev, | ||
| 503 | dev->syscon_camerrx, | ||
| 504 | *field); | ||
| 505 | if (IS_ERR(phy->fields[j])) { | ||
| 506 | cal_err(dev, "Unable to allocate regmap fields\n"); | ||
| 507 | return PTR_ERR(phy->fields[j]); | ||
| 508 | } | ||
| 509 | } | ||
| 510 | } | ||
| 511 | return 0; | ||
| 512 | } | ||
| 513 | |||
| 514 | static const struct regmap_config cal_regmap_config = { | ||
| 515 | .reg_bits = 32, | ||
| 516 | .val_bits = 32, | ||
| 517 | .reg_stride = 4, | ||
| 518 | }; | ||
| 519 | |||
| 520 | static struct regmap *cal_get_camerarx_regmap(struct cal_dev *dev) | ||
| 521 | { | ||
| 522 | struct platform_device *pdev = dev->pdev; | ||
| 523 | struct regmap *regmap; | ||
| 524 | void __iomem *base; | ||
| 525 | u32 reg_io_width; | ||
| 526 | struct regmap_config r_config = cal_regmap_config; | ||
| 527 | struct resource *res; | ||
| 528 | |||
| 529 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
| 530 | "camerrx_control"); | ||
| 531 | base = devm_ioremap_resource(&pdev->dev, res); | ||
| 532 | if (IS_ERR(base)) { | ||
| 533 | cal_err(dev, "failed to ioremap\n"); | ||
| 534 | return ERR_CAST(base); | ||
| 535 | } | ||
| 536 | |||
| 537 | cal_dbg(1, dev, "ioresource %s at %pa - %pa\n", | ||
| 538 | res->name, &res->start, &res->end); | ||
| 539 | |||
| 540 | reg_io_width = 4; | ||
| 541 | r_config.reg_stride = reg_io_width; | ||
| 542 | r_config.val_bits = reg_io_width * 8; | ||
| 543 | r_config.max_register = resource_size(res) - reg_io_width; | ||
| 544 | |||
| 545 | regmap = regmap_init_mmio(NULL, base, &r_config); | ||
| 546 | if (IS_ERR(regmap)) | ||
| 547 | pr_err("regmap init failed\n"); | ||
| 548 | |||
| 549 | return regmap; | ||
| 550 | } | ||
| 551 | |||
| 552 | /* | ||
| 553 | * Control Module CAMERARX block access | ||
| 554 | */ | ||
| 555 | static void camerarx_phy_enable(struct cal_ctx *ctx) | ||
| 556 | { | ||
| 557 | struct cal_csi2_phy *phy; | ||
| 558 | u32 phy_id = ctx->csi2_port - 1; | ||
| 559 | u32 max_lanes; | ||
| 560 | |||
| 561 | phy = &ctx->dev->data->csi2_phy_core[phy_id]; | ||
| 562 | regmap_field_write(phy->fields[F_CAMMODE], 0); | ||
| 563 | /* Always enable all lanes at the phy control level */ | ||
| 564 | max_lanes = (1 << cal_data_get_phy_max_lanes(ctx)) - 1; | ||
| 565 | regmap_field_write(phy->fields[F_LANEENABLE], max_lanes); | ||
| 566 | /* F_CSI_MODE is not present on every architecture */ | ||
| 567 | if (phy->fields[F_CSI_MODE]) | ||
| 568 | regmap_field_write(phy->fields[F_CSI_MODE], 1); | ||
| 569 | regmap_field_write(phy->fields[F_CTRLCLKEN], 1); | ||
| 570 | } | ||
| 571 | |||
| 572 | static void camerarx_phy_disable(struct cal_ctx *ctx) | ||
| 573 | { | ||
| 574 | struct cal_csi2_phy *phy; | ||
| 575 | u32 phy_id = ctx->csi2_port - 1; | ||
| 576 | |||
| 577 | phy = &ctx->dev->data->csi2_phy_core[phy_id]; | ||
| 578 | regmap_field_write(phy->fields[F_CTRLCLKEN], 0); | ||
| 579 | } | ||
| 580 | |||
| 581 | /* | ||
| 582 | * Camera Instance access block | ||
| 583 | */ | ||
| 584 | static struct cc_data *cc_create(struct cal_dev *dev, unsigned int core) | ||
| 585 | { | ||
| 586 | struct platform_device *pdev = dev->pdev; | ||
| 587 | struct cc_data *cc; | ||
| 588 | |||
| 589 | cc = devm_kzalloc(&pdev->dev, sizeof(*cc), GFP_KERNEL); | ||
| 590 | if (!cc) | ||
| 591 | return ERR_PTR(-ENOMEM); | ||
| 592 | |||
| 593 | cc->res = platform_get_resource_byname(pdev, | ||
| 594 | IORESOURCE_MEM, | ||
| 595 | (core == 0) ? | ||
| 596 | "cal_rx_core0" : | ||
| 597 | "cal_rx_core1"); | ||
| 598 | cc->base = devm_ioremap_resource(&pdev->dev, cc->res); | ||
| 599 | if (IS_ERR(cc->base)) { | ||
| 600 | cal_err(dev, "failed to ioremap\n"); | ||
| 601 | return ERR_CAST(cc->base); | ||
| 602 | } | ||
| 603 | |||
| 604 | cal_dbg(1, dev, "ioresource %s at %pa - %pa\n", | ||
| 605 | cc->res->name, &cc->res->start, &cc->res->end); | ||
| 606 | |||
| 607 | return cc; | ||
| 608 | } | ||
| 609 | |||
| 610 | /* | ||
| 611 | * Get Revision and HW info | ||
| 612 | */ | 128 | */ |
| 613 | static void cal_get_hwinfo(struct cal_dev *dev) | ||
| 614 | { | ||
| 615 | u32 revision = 0; | ||
| 616 | u32 hwinfo = 0; | ||
| 617 | |||
| 618 | revision = reg_read(dev, CAL_HL_REVISION); | ||
| 619 | cal_dbg(3, dev, "CAL_HL_REVISION = 0x%08x (expecting 0x40000200)\n", | ||
| 620 | revision); | ||
| 621 | |||
| 622 | hwinfo = reg_read(dev, CAL_HL_HWINFO); | ||
| 623 | cal_dbg(3, dev, "CAL_HL_HWINFO = 0x%08x (expecting 0xA3C90469)\n", | ||
| 624 | hwinfo); | ||
| 625 | } | ||
| 626 | 129 | ||
| 627 | /* | 130 | void cal_quickdump_regs(struct cal_dev *cal) |
| 628 | * Errata i913: CSI2 LDO Needs to be disabled when module is powered on | ||
| 629 | * | ||
| 630 | * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2 | ||
| 631 | * LDOs on the device are disabled if CSI-2 module is powered on | ||
| 632 | * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304 | ||
| 633 | * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high | ||
| 634 | * current draw on the module supply in active mode. | ||
| 635 | * | ||
| 636 | * Errata does not apply when CSI-2 module is powered off | ||
| 637 | * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0). | ||
| 638 | * | ||
| 639 | * SW Workaround: | ||
| 640 | * Set the following register bits to disable the LDO, | ||
| 641 | * which is essentially CSI2 REG10 bit 6: | ||
| 642 | * | ||
| 643 | * Core 0: 0x4845 B828 = 0x0000 0040 | ||
| 644 | * Core 1: 0x4845 B928 = 0x0000 0040 | ||
| 645 | */ | ||
| 646 | static void i913_errata(struct cal_dev *dev, unsigned int port) | ||
| 647 | { | 131 | { |
| 648 | u32 reg10 = reg_read(dev->cc[port], CAL_CSI2_PHY_REG10); | 132 | unsigned int i; |
| 649 | |||
| 650 | set_field(®10, 1, CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK); | ||
| 651 | |||
| 652 | cal_dbg(1, dev, "CSI2_%d_REG10 = 0x%08x\n", port, reg10); | ||
| 653 | reg_write(dev->cc[port], CAL_CSI2_PHY_REG10, reg10); | ||
| 654 | } | ||
| 655 | 133 | ||
| 656 | static void cal_quickdump_regs(struct cal_dev *dev) | 134 | cal_info(cal, "CAL Registers @ 0x%pa:\n", &cal->res->start); |
| 657 | { | ||
| 658 | cal_info(dev, "CAL Registers @ 0x%pa:\n", &dev->res->start); | ||
| 659 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, | 135 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, |
| 660 | (__force const void *)dev->base, | 136 | (__force const void *)cal->base, |
| 661 | resource_size(dev->res), false); | 137 | resource_size(cal->res), false); |
| 662 | 138 | ||
| 663 | if (dev->ctx[0]) { | 139 | for (i = 0; i < ARRAY_SIZE(cal->phy); ++i) { |
| 664 | cal_info(dev, "CSI2 Core 0 Registers @ %pa:\n", | 140 | struct cal_camerarx *phy = cal->phy[i]; |
| 665 | &dev->ctx[0]->cc->res->start); | 141 | |
| 666 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, | 142 | if (!phy) |
| 667 | (__force const void *)dev->ctx[0]->cc->base, | 143 | continue; |
| 668 | resource_size(dev->ctx[0]->cc->res), | ||
| 669 | false); | ||
| 670 | } | ||
| 671 | 144 | ||
| 672 | if (dev->ctx[1]) { | 145 | cal_info(cal, "CSI2 Core %u Registers @ %pa:\n", i, |
| 673 | cal_info(dev, "CSI2 Core 1 Registers @ %pa:\n", | 146 | &phy->res->start); |
| 674 | &dev->ctx[1]->cc->res->start); | ||
| 675 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, | 147 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, |
| 676 | (__force const void *)dev->ctx[1]->cc->base, | 148 | (__force const void *)phy->base, |
| 677 | resource_size(dev->ctx[1]->cc->res), | 149 | resource_size(phy->res), |
| 678 | false); | 150 | false); |
| 679 | } | 151 | } |
| 680 | } | 152 | } |
| 681 | 153 | ||
| 682 | /* | 154 | /* ------------------------------------------------------------------ |
| 683 | * Enable the expected IRQ sources | 155 | * Context Management |
| 156 | * ------------------------------------------------------------------ | ||
| 684 | */ | 157 | */ |
| 685 | static void enable_irqs(struct cal_ctx *ctx) | ||
| 686 | { | ||
| 687 | u32 val; | ||
| 688 | |||
| 689 | const u32 cio_err_mask = | ||
| 690 | CAL_CSI2_COMPLEXIO_IRQ_LANE_ERRORS_MASK | | ||
| 691 | CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK | | ||
| 692 | CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK | | ||
| 693 | CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK; | ||
| 694 | |||
| 695 | /* Enable CIO error irqs */ | ||
| 696 | reg_write(ctx->dev, CAL_HL_IRQENABLE_SET(1), | ||
| 697 | CAL_HL_IRQ_CIO_MASK(ctx->csi2_port)); | ||
| 698 | reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_IRQENABLE(ctx->csi2_port), | ||
| 699 | cio_err_mask); | ||
| 700 | |||
| 701 | /* Always enable OCPO error */ | ||
| 702 | reg_write(ctx->dev, CAL_HL_IRQENABLE_SET(1), CAL_HL_IRQ_OCPO_ERR_MASK); | ||
| 703 | |||
| 704 | /* Enable IRQ_WDMA_END 0/1 */ | ||
| 705 | val = 0; | ||
| 706 | set_field(&val, 1, CAL_HL_IRQ_MASK(ctx->csi2_port)); | ||
| 707 | reg_write(ctx->dev, CAL_HL_IRQENABLE_SET(2), val); | ||
| 708 | /* Enable IRQ_WDMA_START 0/1 */ | ||
| 709 | val = 0; | ||
| 710 | set_field(&val, 1, CAL_HL_IRQ_MASK(ctx->csi2_port)); | ||
| 711 | reg_write(ctx->dev, CAL_HL_IRQENABLE_SET(3), val); | ||
| 712 | /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */ | ||
| 713 | reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0xFF000000); | ||
| 714 | } | ||
| 715 | |||
| 716 | static void disable_irqs(struct cal_ctx *ctx) | ||
| 717 | { | ||
| 718 | u32 val; | ||
| 719 | |||
| 720 | /* Disable CIO error irqs */ | ||
| 721 | reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(1), | ||
| 722 | CAL_HL_IRQ_CIO_MASK(ctx->csi2_port)); | ||
| 723 | reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_IRQENABLE(ctx->csi2_port), | ||
| 724 | 0); | ||
| 725 | |||
| 726 | /* Disable IRQ_WDMA_END 0/1 */ | ||
| 727 | val = 0; | ||
| 728 | set_field(&val, 1, CAL_HL_IRQ_MASK(ctx->csi2_port)); | ||
| 729 | reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(2), val); | ||
| 730 | /* Disable IRQ_WDMA_START 0/1 */ | ||
| 731 | val = 0; | ||
| 732 | set_field(&val, 1, CAL_HL_IRQ_MASK(ctx->csi2_port)); | ||
| 733 | reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(3), val); | ||
| 734 | /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */ | ||
| 735 | reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0); | ||
| 736 | } | ||
| 737 | |||
| 738 | static void csi2_cio_power(struct cal_ctx *ctx, bool enable) | ||
| 739 | { | ||
| 740 | u32 target_state; | ||
| 741 | unsigned int i; | ||
| 742 | |||
| 743 | target_state = enable ? CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON : | ||
| 744 | CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF; | ||
| 745 | |||
| 746 | reg_write_field(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), | ||
| 747 | target_state, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK); | ||
| 748 | |||
| 749 | for (i = 0; i < 10; i++) { | ||
| 750 | u32 current_state; | ||
| 751 | |||
| 752 | current_state = reg_read_field(ctx->dev, | ||
| 753 | CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), | ||
| 754 | CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK); | ||
| 755 | |||
| 756 | if (current_state == target_state) | ||
| 757 | break; | ||
| 758 | |||
| 759 | usleep_range(1000, 1100); | ||
| 760 | } | ||
| 761 | |||
| 762 | if (i == 10) | ||
| 763 | ctx_err(ctx, "Failed to power %s complexio\n", | ||
| 764 | enable ? "up" : "down"); | ||
| 765 | } | ||
| 766 | |||
| 767 | static void csi2_phy_config(struct cal_ctx *ctx); | ||
| 768 | |||
| 769 | static void csi2_phy_init(struct cal_ctx *ctx) | ||
| 770 | { | ||
| 771 | u32 val; | ||
| 772 | u32 sscounter; | ||
| 773 | |||
| 774 | /* Steps | ||
| 775 | * 1. Configure D-PHY mode and enable required lanes | ||
| 776 | * 2. Reset complex IO - Wait for completion of reset | ||
| 777 | * Note if the external sensor is not sending byte clock, | ||
| 778 | * the reset will timeout | ||
| 779 | * 3 Program Stop States | ||
| 780 | * A. Program THS_TERM, THS_SETTLE, etc... Timings parameters | ||
| 781 | * in terms of DDR clock periods | ||
| 782 | * B. Enable stop state transition timeouts | ||
| 783 | * 4.Force FORCERXMODE | ||
| 784 | * D. Enable pull down using pad control | ||
| 785 | * E. Power up PHY | ||
| 786 | * F. Wait for power up completion | ||
| 787 | * G. Wait for all enabled lane to reach stop state | ||
| 788 | * H. Disable pull down using pad control | ||
| 789 | */ | ||
| 790 | |||
| 791 | /* 1. Configure D-PHY mode and enable required lanes */ | ||
| 792 | camerarx_phy_enable(ctx); | ||
| 793 | |||
| 794 | /* 2. Reset complex IO - Do not wait for reset completion */ | ||
| 795 | reg_write_field(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), | ||
| 796 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL, | ||
| 797 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); | ||
| 798 | ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x De-assert Complex IO Reset\n", | ||
| 799 | ctx->csi2_port, | ||
| 800 | reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port))); | ||
| 801 | |||
| 802 | /* Dummy read to allow SCP reset to complete */ | ||
| 803 | reg_read(ctx->cc, CAL_CSI2_PHY_REG0); | ||
| 804 | |||
| 805 | /* 3.A. Program Phy Timing Parameters */ | ||
| 806 | csi2_phy_config(ctx); | ||
| 807 | |||
| 808 | /* 3.B. Program Stop States */ | ||
| 809 | /* | ||
| 810 | * The stop-state-counter is based on fclk cycles, and we always use | ||
| 811 | * the x16 and x4 settings, so stop-state-timeout = | ||
| 812 | * fclk-cycle * 16 * 4 * counter. | ||
| 813 | * | ||
| 814 | * Stop-state-timeout must be more than 100us as per CSI2 spec, so we | ||
| 815 | * calculate a timeout that's 100us (rounding up). | ||
| 816 | */ | ||
| 817 | sscounter = DIV_ROUND_UP(clk_get_rate(ctx->dev->fclk), 10000 * 16 * 4); | ||
| 818 | |||
| 819 | val = reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port)); | ||
| 820 | set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK); | ||
| 821 | set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK); | ||
| 822 | set_field(&val, sscounter, CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK); | ||
| 823 | reg_write(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port), val); | ||
| 824 | ctx_dbg(3, ctx, "CAL_CSI2_TIMING(%d) = 0x%08x Stop States\n", | ||
| 825 | ctx->csi2_port, | ||
| 826 | reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port))); | ||
| 827 | |||
| 828 | /* 4. Force FORCERXMODE */ | ||
| 829 | reg_write_field(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port), | ||
| 830 | 1, CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK); | ||
| 831 | ctx_dbg(3, ctx, "CAL_CSI2_TIMING(%d) = 0x%08x Force RXMODE\n", | ||
| 832 | ctx->csi2_port, | ||
| 833 | reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port))); | ||
| 834 | |||
| 835 | /* E. Power up the PHY using the complex IO */ | ||
| 836 | csi2_cio_power(ctx, true); | ||
| 837 | } | ||
| 838 | |||
| 839 | static void csi2_wait_complexio_reset(struct cal_ctx *ctx) | ||
| 840 | { | ||
| 841 | unsigned long timeout; | ||
| 842 | |||
| 843 | timeout = jiffies + msecs_to_jiffies(750); | ||
| 844 | while (time_before(jiffies, timeout)) { | ||
| 845 | if (reg_read_field(ctx->dev, | ||
| 846 | CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), | ||
| 847 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == | ||
| 848 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) | ||
| 849 | break; | ||
| 850 | usleep_range(500, 5000); | ||
| 851 | } | ||
| 852 | |||
| 853 | if (reg_read_field(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), | ||
| 854 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) != | ||
| 855 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED) | ||
| 856 | ctx_err(ctx, "Timeout waiting for Complex IO reset done\n"); | ||
| 857 | } | ||
| 858 | |||
| 859 | static void csi2_wait_stop_state(struct cal_ctx *ctx) | ||
| 860 | { | ||
| 861 | unsigned long timeout; | ||
| 862 | |||
| 863 | timeout = jiffies + msecs_to_jiffies(750); | ||
| 864 | while (time_before(jiffies, timeout)) { | ||
| 865 | if (reg_read_field(ctx->dev, | ||
| 866 | CAL_CSI2_TIMING(ctx->csi2_port), | ||
| 867 | CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) == 0) | ||
| 868 | break; | ||
| 869 | usleep_range(500, 5000); | ||
| 870 | } | ||
| 871 | |||
| 872 | if (reg_read_field(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port), | ||
| 873 | CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) != 0) | ||
| 874 | ctx_err(ctx, "Timeout waiting for stop state\n"); | ||
| 875 | } | ||
| 876 | |||
| 877 | static void csi2_wait_for_phy(struct cal_ctx *ctx) | ||
| 878 | { | ||
| 879 | /* Steps | ||
| 880 | * 2. Wait for completion of reset | ||
| 881 | * Note if the external sensor is not sending byte clock, | ||
| 882 | * the reset will timeout | ||
| 883 | * 4.Force FORCERXMODE | ||
| 884 | * G. Wait for all enabled lane to reach stop state | ||
| 885 | * H. Disable pull down using pad control | ||
| 886 | */ | ||
| 887 | |||
| 888 | /* 2. Wait for reset completion */ | ||
| 889 | csi2_wait_complexio_reset(ctx); | ||
| 890 | |||
| 891 | /* 4. G. Wait for all enabled lane to reach stop state */ | ||
| 892 | csi2_wait_stop_state(ctx); | ||
| 893 | |||
| 894 | ctx_dbg(1, ctx, "CSI2_%d_REG1 = 0x%08x (Bit(31,28) should be set!)\n", | ||
| 895 | (ctx->csi2_port - 1), reg_read(ctx->cc, CAL_CSI2_PHY_REG1)); | ||
| 896 | } | ||
| 897 | |||
| 898 | static void csi2_phy_deinit(struct cal_ctx *ctx) | ||
| 899 | { | ||
| 900 | int i; | ||
| 901 | |||
| 902 | csi2_cio_power(ctx, false); | ||
| 903 | |||
| 904 | /* Assert Comple IO Reset */ | ||
| 905 | reg_write_field(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), | ||
| 906 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL, | ||
| 907 | CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); | ||
| 908 | |||
| 909 | /* Wait for power down completion */ | ||
| 910 | for (i = 0; i < 10; i++) { | ||
| 911 | if (reg_read_field(ctx->dev, | ||
| 912 | CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), | ||
| 913 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == | ||
| 914 | CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING) | ||
| 915 | break; | ||
| 916 | usleep_range(1000, 1100); | ||
| 917 | } | ||
| 918 | ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset (%d) %s\n", | ||
| 919 | ctx->csi2_port, | ||
| 920 | reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)), i, | ||
| 921 | (i >= 10) ? "(timeout)" : ""); | ||
| 922 | |||
| 923 | /* Disable the phy */ | ||
| 924 | camerarx_phy_disable(ctx); | ||
| 925 | } | ||
| 926 | |||
| 927 | static void csi2_lane_config(struct cal_ctx *ctx) | ||
| 928 | { | ||
| 929 | u32 val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)); | ||
| 930 | u32 lane_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK; | ||
| 931 | u32 polarity_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK; | ||
| 932 | struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = | ||
| 933 | &ctx->endpoint.bus.mipi_csi2; | ||
| 934 | int lane; | ||
| 935 | |||
| 936 | set_field(&val, mipi_csi2->clock_lane + 1, lane_mask); | ||
| 937 | set_field(&val, mipi_csi2->lane_polarities[0], polarity_mask); | ||
| 938 | for (lane = 0; lane < mipi_csi2->num_data_lanes; lane++) { | ||
| 939 | /* | ||
| 940 | * Every lane are one nibble apart starting with the | ||
| 941 | * clock followed by the data lanes so shift masks by 4. | ||
| 942 | */ | ||
| 943 | lane_mask <<= 4; | ||
| 944 | polarity_mask <<= 4; | ||
| 945 | set_field(&val, mipi_csi2->data_lanes[lane] + 1, lane_mask); | ||
| 946 | set_field(&val, mipi_csi2->lane_polarities[lane + 1], | ||
| 947 | polarity_mask); | ||
| 948 | } | ||
| 949 | |||
| 950 | reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), val); | ||
| 951 | ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n", | ||
| 952 | ctx->csi2_port, val); | ||
| 953 | } | ||
| 954 | |||
| 955 | static void csi2_ppi_enable(struct cal_ctx *ctx) | ||
| 956 | { | ||
| 957 | reg_write(ctx->dev, CAL_CSI2_PPI_CTRL(ctx->csi2_port), BIT(3)); | ||
| 958 | reg_write_field(ctx->dev, CAL_CSI2_PPI_CTRL(ctx->csi2_port), | ||
| 959 | 1, CAL_CSI2_PPI_CTRL_IF_EN_MASK); | ||
| 960 | } | ||
| 961 | |||
| 962 | static void csi2_ppi_disable(struct cal_ctx *ctx) | ||
| 963 | { | ||
| 964 | reg_write_field(ctx->dev, CAL_CSI2_PPI_CTRL(ctx->csi2_port), | ||
| 965 | 0, CAL_CSI2_PPI_CTRL_IF_EN_MASK); | ||
| 966 | } | ||
| 967 | 158 | ||
| 968 | static void csi2_ctx_config(struct cal_ctx *ctx) | 159 | void cal_ctx_csi2_config(struct cal_ctx *ctx) |
| 969 | { | 160 | { |
| 970 | u32 val; | 161 | u32 val; |
| 971 | 162 | ||
| 972 | val = reg_read(ctx->dev, CAL_CSI2_CTX0(ctx->csi2_port)); | 163 | val = cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index)); |
| 973 | set_field(&val, ctx->csi2_port, CAL_CSI2_CTX_CPORT_MASK); | 164 | cal_set_field(&val, ctx->cport, CAL_CSI2_CTX_CPORT_MASK); |
| 974 | /* | 165 | /* |
| 975 | * DT type: MIPI CSI-2 Specs | 166 | * DT type: MIPI CSI-2 Specs |
| 976 | * 0x1: All - DT filter is disabled | 167 | * 0x1: All - DT filter is disabled |
| @@ -979,19 +170,18 @@ static void csi2_ctx_config(struct cal_ctx *ctx) · 2 unmodified lines | |||
| 979 | * 0x2A: RAW8 1 pixel = 1 byte | 170 | * 0x2A: RAW8 1 pixel = 1 byte |
| 980 | * 0x1E: YUV422 2 pixels = 4 bytes | 171 | * 0x1E: YUV422 2 pixels = 4 bytes |
| 981 | */ | 172 | */ |
| 982 | set_field(&val, 0x1, CAL_CSI2_CTX_DT_MASK); | 173 | cal_set_field(&val, 0x1, CAL_CSI2_CTX_DT_MASK); |
| 983 | /* Virtual Channel from the CSI2 sensor usually 0! */ | 174 | cal_set_field(&val, 0, CAL_CSI2_CTX_VC_MASK); |
| 984 | set_field(&val, ctx->virtual_channel, CAL_CSI2_CTX_VC_MASK); | 175 | cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK); |
| 985 | set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK); | 176 | cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); |
| 986 | set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); | 177 | cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, |
| 987 | set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, | 178 | CAL_CSI2_CTX_PACK_MODE_MASK); |
| 988 | CAL_CSI2_CTX_PACK_MODE_MASK); | 179 | cal_write(ctx->cal, CAL_CSI2_CTX0(ctx->index), val); |
| 989 | reg_write(ctx->dev, CAL_CSI2_CTX0(ctx->csi2_port), val); | 180 | ctx_dbg(3, ctx, "CAL_CSI2_CTX0(%d) = 0x%08x\n", ctx->index, |
| 990 | ctx_dbg(3, ctx, "CAL_CSI2_CTX0(%d) = 0x%08x\n", ctx->csi2_port, | 181 | cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index))); |
| 991 | reg_read(ctx->dev, CAL_CSI2_CTX0(ctx->csi2_port))); | ||
| 992 | } | 182 | } |
| 993 | 183 | ||
| 994 | static void pix_proc_config(struct cal_ctx *ctx) | 184 | void cal_ctx_pix_proc_config(struct cal_ctx *ctx) |
| 995 | { | 185 | { |
| 996 | u32 val, extract, pack; | 186 | u32 val, extract, pack; |
| 997 | 187 | ||
| @@ -1022,7 +212,7 @@ static void pix_proc_config(struct cal_ctx *ctx) · 24 unmodified lines | |||
| 1022 | * | 212 | * |
| 1023 | * Instead of failing here just use 8 bpp as a default. | 213 | * Instead of failing here just use 8 bpp as a default. |
| 1024 | */ | 214 | */ |
| 1025 | dev_warn_once(&ctx->dev->pdev->dev, | 215 | dev_warn_once(ctx->cal->dev, |
| 1026 | "%s:%d:%s: bpp:%d unsupported! Overwritten with 8.\n", | 216 | "%s:%d:%s: bpp:%d unsupported! Overwritten with 8.\n", |
| 1027 | __FILE__, __LINE__, __func__, ctx->fmt->bpp); | 217 | __FILE__, __LINE__, __func__, ctx->fmt->bpp); |
| 1028 | extract = CAL_PIX_PROC_EXTRACT_B8; | 218 | extract = CAL_PIX_PROC_EXTRACT_B8; |
| @@ -1030,145 +220,82 @@ static void pix_proc_config(struct cal_ctx *ctx) · 1 unmodified line | |||
| 1030 | break; | 220 | break; |
| 1031 | } | 221 | } |
| 1032 | 222 | ||
| 1033 | val = reg_read(ctx->dev, CAL_PIX_PROC(ctx->csi2_port)); | 223 | val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->index)); |
| 1034 | set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK); | 224 | cal_set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK); |
| 1035 | set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK); | 225 | cal_set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK); |
| 1036 | set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK); | 226 | cal_set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK); |
| 1037 | set_field(&val, pack, CAL_PIX_PROC_PACK_MASK); | 227 | cal_set_field(&val, pack, CAL_PIX_PROC_PACK_MASK); |
| 1038 | set_field(&val, ctx->csi2_port, CAL_PIX_PROC_CPORT_MASK); | 228 | cal_set_field(&val, ctx->cport, CAL_PIX_PROC_CPORT_MASK); |
| 1039 | set_field(&val, 1, CAL_PIX_PROC_EN_MASK); | 229 | cal_set_field(&val, 1, CAL_PIX_PROC_EN_MASK); |
| 1040 | reg_write(ctx->dev, CAL_PIX_PROC(ctx->csi2_port), val); | 230 | cal_write(ctx->cal, CAL_PIX_PROC(ctx->index), val); |
| 1041 | ctx_dbg(3, ctx, "CAL_PIX_PROC(%d) = 0x%08x\n", ctx->csi2_port, | 231 | ctx_dbg(3, ctx, "CAL_PIX_PROC(%d) = 0x%08x\n", ctx->index, |
| 1042 | reg_read(ctx->dev, CAL_PIX_PROC(ctx->csi2_port))); | 232 | cal_read(ctx->cal, CAL_PIX_PROC(ctx->index))); |
| 1043 | } | 233 | } |
| 1044 | 234 | ||
| 1045 | static void cal_wr_dma_config(struct cal_ctx *ctx, | 235 | void cal_ctx_wr_dma_config(struct cal_ctx *ctx, unsigned int width, |
| 1046 | unsigned int width, unsigned int height) | 236 | unsigned int height) |
| 1047 | { | 237 | { |
| 1048 | u32 val; | 238 | u32 val; |
| 1049 | 239 | ||
| 1050 | val = reg_read(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port)); | 240 | val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)); |
| 1051 | set_field(&val, ctx->csi2_port, CAL_WR_DMA_CTRL_CPORT_MASK); | 241 | cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK); |
| 1052 | set_field(&val, height, CAL_WR_DMA_CTRL_YSIZE_MASK); | 242 | cal_set_field(&val, height, CAL_WR_DMA_CTRL_YSIZE_MASK); |
| 1053 | set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT, | 243 | cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT, |
| 1054 | CAL_WR_DMA_CTRL_DTAG_MASK); | 244 | CAL_WR_DMA_CTRL_DTAG_MASK); |
| 1055 | set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, | 245 | cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, |
| 1056 | CAL_WR_DMA_CTRL_MODE_MASK); | 246 | CAL_WR_DMA_CTRL_MODE_MASK); |
| 1057 | set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, | 247 | cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, |
| 1058 | CAL_WR_DMA_CTRL_PATTERN_MASK); | 248 | CAL_WR_DMA_CTRL_PATTERN_MASK); |
| 1059 | set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); | 249 | cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); |
| 1060 | reg_write(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port), val); | 250 | cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val); |
| 1061 | ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->csi2_port, | 251 | ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->index, |
| 1062 | reg_read(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port))); | 252 | cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index))); |
| 1063 | 253 | ||
| 1064 | /* | 254 | /* |
| 1065 | * width/16 not sure but giving it a whirl. | 255 | * width/16 not sure but giving it a whirl. |
| 1066 | * zero does not work right | 256 | * zero does not work right |
| 1067 | */ | 257 | */ |
| 1068 | reg_write_field(ctx->dev, | 258 | cal_write_field(ctx->cal, |
| 1069 | CAL_WR_DMA_OFST(ctx->csi2_port), | 259 | CAL_WR_DMA_OFST(ctx->index), |
| 1070 | (width / 16), | 260 | (width / 16), |
| 1071 | CAL_WR_DMA_OFST_MASK); | 261 | CAL_WR_DMA_OFST_MASK); |
| 1072 | ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->csi2_port, | 262 | ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->index, |
| 1073 | reg_read(ctx->dev, CAL_WR_DMA_OFST(ctx->csi2_port))); | 263 | cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->index))); |
| 1074 | 264 | ||
| 1075 | val = reg_read(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port)); | 265 | val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index)); |
| 1076 | /* 64 bit word means no skipping */ | 266 | /* 64 bit word means no skipping */ |
| 1077 | set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK); | 267 | cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK); |
| 1078 | /* | 268 | /* |
| 1079 | * (width*8)/64 this should be size of an entire line | 269 | * (width*8)/64 this should be size of an entire line |
| 1080 | * in 64bit word but 0 means all data until the end | 270 | * in 64bit word but 0 means all data until the end |
| 1081 | * is detected automagically | 271 | * is detected automagically |
| 1082 | */ | 272 | */ |
| 1083 | set_field(&val, (width / 8), CAL_WR_DMA_XSIZE_MASK); | 273 | cal_set_field(&val, (width / 8), CAL_WR_DMA_XSIZE_MASK); |
| 1084 | reg_write(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port), val); | 274 | cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index), val); |
| 1085 | ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->csi2_port, | 275 | ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->index, |
| 1086 | reg_read(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port))); | 276 | cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index))); |
| 1087 | |||
| 1088 | val = reg_read(ctx->dev, CAL_CTRL); | ||
| 1089 | set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, CAL_CTRL_BURSTSIZE_MASK); | ||
| 1090 | set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK); | ||
| 1091 | set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, | ||
| 1092 | CAL_CTRL_POSTED_WRITES_MASK); | ||
| 1093 | set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK); | ||
| 1094 | set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK); | ||
| 1095 | reg_write(ctx->dev, CAL_CTRL, val); | ||
| 1096 | ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", reg_read(ctx->dev, CAL_CTRL)); | ||
| 1097 | } | ||
| 1098 | 277 | ||
| 1099 | static void cal_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr) | 278 | val = cal_read(ctx->cal, CAL_CTRL); |
| 1100 | { | 279 | cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, |
| 1101 | reg_write(ctx->dev, CAL_WR_DMA_ADDR(ctx->csi2_port), dmaaddr); | 280 | CAL_CTRL_BURSTSIZE_MASK); |
| 281 | cal_set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK); | ||
| 282 | cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, | ||
| 283 | CAL_CTRL_POSTED_WRITES_MASK); | ||
| 284 | cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK); | ||
| 285 | cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK); | ||
| 286 | cal_write(ctx->cal, CAL_CTRL, val); | ||
| 287 | ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", cal_read(ctx->cal, CAL_CTRL)); | ||
| 1102 | } | 288 | } |
| 1103 | 289 | ||
| 1104 | /* | 290 | void cal_ctx_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr) |
| 1105 | * TCLK values are OK at their reset values | ||
| 1106 | */ | ||
| 1107 | #define TCLK_TERM 0 | ||
| 1108 | #define TCLK_MISS 1 | ||
| 1109 | #define TCLK_SETTLE 14 | ||
| 1110 | |||
| 1111 | static void csi2_phy_config(struct cal_ctx *ctx) | ||
| 1112 | { | 291 | { |
| 1113 | unsigned int reg0, reg1; | 292 | cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->index), dmaaddr); |
| 1114 | unsigned int ths_term, ths_settle; | ||
| 1115 | unsigned int csi2_ddrclk_khz; | ||
| 1116 | struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = | ||
| 1117 | &ctx->endpoint.bus.mipi_csi2; | ||
| 1118 | u32 num_lanes = mipi_csi2->num_data_lanes; | ||
| 1119 | |||
| 1120 | /* DPHY timing configuration */ | ||
| 1121 | /* CSI-2 is DDR and we only count used lanes. */ | ||
| 1122 | csi2_ddrclk_khz = ctx->external_rate / 1000 | ||
| 1123 | / (2 * num_lanes) * ctx->fmt->bpp; | ||
| 1124 | ctx_dbg(1, ctx, "csi2_ddrclk_khz: %d\n", csi2_ddrclk_khz); | ||
| 1125 | |||
| 1126 | /* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */ | ||
| 1127 | ths_term = 20 * csi2_ddrclk_khz / 1000000; | ||
| 1128 | ctx_dbg(1, ctx, "ths_term: %d (0x%02x)\n", ths_term, ths_term); | ||
| 1129 | |||
| 1130 | /* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */ | ||
| 1131 | ths_settle = (105 * csi2_ddrclk_khz / 1000000) + 4; | ||
| 1132 | ctx_dbg(1, ctx, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle); | ||
| 1133 | |||
| 1134 | reg0 = reg_read(ctx->cc, CAL_CSI2_PHY_REG0); | ||
| 1135 | set_field(®0, CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE, | ||
| 1136 | CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK); | ||
| 1137 | set_field(®0, ths_term, CAL_CSI2_PHY_REG0_THS_TERM_MASK); | ||
| 1138 | set_field(®0, ths_settle, CAL_CSI2_PHY_REG0_THS_SETTLE_MASK); | ||
| 1139 | |||
| 1140 | ctx_dbg(1, ctx, "CSI2_%d_REG0 = 0x%08x\n", (ctx->csi2_port - 1), reg0); | ||
| 1141 | reg_write(ctx->cc, CAL_CSI2_PHY_REG0, reg0); | ||
| 1142 | |||
| 1143 | reg1 = reg_read(ctx->cc, CAL_CSI2_PHY_REG1); | ||
| 1144 | set_field(®1, TCLK_TERM, CAL_CSI2_PHY_REG1_TCLK_TERM_MASK); | ||
| 1145 | set_field(®1, 0xb8, CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK); | ||
| 1146 | set_field(®1, TCLK_MISS, CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK); | ||
| 1147 | set_field(®1, TCLK_SETTLE, CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK); | ||
| 1148 | |||
| 1149 | ctx_dbg(1, ctx, "CSI2_%d_REG1 = 0x%08x\n", (ctx->csi2_port - 1), reg1); | ||
| 1150 | reg_write(ctx->cc, CAL_CSI2_PHY_REG1, reg1); | ||
| 1151 | } | 293 | } |
| 1152 | 294 | ||
| 1153 | static int cal_get_external_info(struct cal_ctx *ctx) | 295 | /* ------------------------------------------------------------------ |
| 1154 | { | 296 | * IRQ Handling |
| 1155 | struct v4l2_ctrl *ctrl; | 297 | * ------------------------------------------------------------------ |
| 1156 | 298 | */ | |
| 1157 | if (!ctx->sensor) | ||
| 1158 | return -ENODEV; | ||
| 1159 | |||
| 1160 | ctrl = v4l2_ctrl_find(ctx->sensor->ctrl_handler, V4L2_CID_PIXEL_RATE); | ||
| 1161 | if (!ctrl) { | ||
| 1162 | ctx_err(ctx, "no pixel rate control in subdev: %s\n", | ||
| 1163 | ctx->sensor->name); | ||
| 1164 | return -EPIPE; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | ctx->external_rate = v4l2_ctrl_g_ctrl_int64(ctrl); | ||
| 1168 | ctx_dbg(3, ctx, "sensor Pixel Rate: %d\n", ctx->external_rate); | ||
| 1169 | |||
| 1170 | return 0; | ||
| 1171 | } | ||
| 1172 | 299 | ||
| 1173 | static inline void cal_schedule_next_buffer(struct cal_ctx *ctx) | 300 | static inline void cal_schedule_next_buffer(struct cal_ctx *ctx) |
| 1174 | { | 301 | { |
| @@ -1181,7 +308,7 @@ static inline void cal_schedule_next_buffer(struct cal_ctx *ctx) · 6 unmodified lines | |||
| 1181 | list_del(&buf->list); | 308 | list_del(&buf->list); |
| 1182 | 309 | ||
| 1183 | addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); | 310 | addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); |
| 1184 | cal_wr_dma_addr(ctx, addr); | 311 | cal_ctx_wr_dma_addr(ctx, addr); |
| 1185 | } | 312 | } |
| 1186 | 313 | ||
| 1187 | static inline void cal_process_buffer_complete(struct cal_ctx *ctx) | 314 | static inline void cal_process_buffer_complete(struct cal_ctx *ctx) |
| @@ -1194,52 +321,47 @@ static inline void cal_process_buffer_complete(struct cal_ctx *ctx) · 6 unmodified lines | |||
| 1194 | ctx->cur_frm = ctx->next_frm; | 321 | ctx->cur_frm = ctx->next_frm; |
| 1195 | } | 322 | } |
| 1196 | 323 | ||
| 1197 | #define isvcirqset(irq, vc, ff) (irq & \ | ||
| 1198 | (CAL_CSI2_VC_IRQENABLE_ ##ff ##_IRQ_##vc ##_MASK)) | ||
| 1199 | |||
| 1200 | #define isportirqset(irq, port) (irq & CAL_HL_IRQ_MASK(port)) | ||
| 1201 | |||
| 1202 | static irqreturn_t cal_irq(int irq_cal, void *data) | 324 | static irqreturn_t cal_irq(int irq_cal, void *data) |
| 1203 | { | 325 | { |
| 1204 | struct cal_dev *dev = (struct cal_dev *)data; | 326 | struct cal_dev *cal = data; |
| 1205 | struct cal_ctx *ctx; | 327 | struct cal_ctx *ctx; |
| 1206 | struct cal_dmaqueue *dma_q; | 328 | struct cal_dmaqueue *dma_q; |
| 1207 | u32 irqst1, irqst2, irqst3; | 329 | u32 status; |
| 1208 | 330 | ||
| 1209 | irqst1 = reg_read(dev, CAL_HL_IRQSTATUS(1)); | 331 | status = cal_read(cal, CAL_HL_IRQSTATUS(0)); |
| 1210 | if (irqst1) { | 332 | if (status) { |
| 1211 | int i; | 333 | unsigned int i; |
| 1212 | 334 | ||
| 1213 | reg_write(dev, CAL_HL_IRQSTATUS(1), irqst1); | 335 | cal_write(cal, CAL_HL_IRQSTATUS(0), status); |
| 1214 | 336 | ||
| 1215 | if (irqst1 & CAL_HL_IRQ_OCPO_ERR_MASK) | 337 | if (status & CAL_HL_IRQ_OCPO_ERR_MASK) |
| 1216 | dev_err_ratelimited(&dev->pdev->dev, "OCPO ERROR\n"); | 338 | dev_err_ratelimited(cal->dev, "OCPO ERROR\n"); |
| 1217 | 339 | ||
| 1218 | for (i = 1; i <= 2; ++i) { | 340 | for (i = 0; i < CAL_NUM_CSI2_PORTS; ++i) { |
| 1219 | if (irqst1 & CAL_HL_IRQ_CIO_MASK(i)) { | 341 | if (status & CAL_HL_IRQ_CIO_MASK(i)) { |
| 1220 | u32 cio_stat = reg_read(dev, | 342 | u32 cio_stat = cal_read(cal, |
| 1221 | CAL_CSI2_COMPLEXIO_IRQSTATUS(i)); | 343 | CAL_CSI2_COMPLEXIO_IRQSTATUS(i)); |
| 1222 | 344 | ||
| 1223 | dev_err_ratelimited(&dev->pdev->dev, | 345 | dev_err_ratelimited(cal->dev, |
| 1224 | "CIO%d error: %#08x\n", i, cio_stat); | 346 | "CIO%u error: %#08x\n", i, cio_stat); |
| 1225 | 347 | ||
| 1226 | reg_write(dev, CAL_CSI2_COMPLEXIO_IRQSTATUS(i), | 348 | cal_write(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i), |
| 1227 | cio_stat); | 349 | cio_stat); |
| 1228 | } | 350 | } |
| 1229 | } | 351 | } |
| 1230 | } | 352 | } |
| 1231 | 353 | ||
| 1232 | /* Check which DMA just finished */ | 354 | /* Check which DMA just finished */ |
| 1233 | irqst2 = reg_read(dev, CAL_HL_IRQSTATUS(2)); | 355 | status = cal_read(cal, CAL_HL_IRQSTATUS(1)); |
| 1234 | if (irqst2) { | 356 | if (status) { |
| 1235 | int i; | 357 | unsigned int i; |
| 1236 | 358 | ||
| 1237 | /* Clear Interrupt status */ | 359 | /* Clear Interrupt status */ |
| 1238 | reg_write(dev, CAL_HL_IRQSTATUS(2), irqst2); | 360 | cal_write(cal, CAL_HL_IRQSTATUS(1), status); |
| 1239 | 361 | ||
| 1240 | for (i = 1; i <= 2; ++i) { | 362 | for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { |
| 1241 | if (isportirqset(irqst2, i)) { | 363 | if (status & CAL_HL_IRQ_MASK(i)) { |
| 1242 | ctx = dev->ctx[i - 1]; | 364 | ctx = cal->ctx[i]; |
| 1243 | 365 | ||
| 1244 | spin_lock(&ctx->slock); | 366 | spin_lock(&ctx->slock); |
| 1245 | ctx->dma_act = false; | 367 | ctx->dma_act = false; |
| @@ -1253,16 +375,16 @@ static irqreturn_t cal_irq(int irq_cal, void *data) · 7 unmodified lines | |||
| 1253 | } | 375 | } |
| 1254 | 376 | ||
| 1255 | /* Check which DMA just started */ | 377 | /* Check which DMA just started */ |
| 1256 | irqst3 = reg_read(dev, CAL_HL_IRQSTATUS(3)); | 378 | status = cal_read(cal, CAL_HL_IRQSTATUS(2)); |
| 1257 | if (irqst3) { | 379 | if (status) { |
| 1258 | int i; | 380 | unsigned int i; |
| 1259 | 381 | ||
| 1260 | /* Clear Interrupt status */ | 382 | /* Clear Interrupt status */ |
| 1261 | reg_write(dev, CAL_HL_IRQSTATUS(3), irqst3); | 383 | cal_write(cal, CAL_HL_IRQSTATUS(2), status); |
| 1262 | 384 | ||
| 1263 | for (i = 1; i <= 2; ++i) { | 385 | for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { |
| 1264 | if (isportirqset(irqst3, i)) { | 386 | if (status & CAL_HL_IRQ_MASK(i)) { |
| 1265 | ctx = dev->ctx[i - 1]; | 387 | ctx = cal->ctx[i]; |
| 1266 | dma_q = &ctx->vidq; | 388 | dma_q = &ctx->vidq; |
| 1267 | 389 | ||
| 1268 | spin_lock(&ctx->slock); | 390 | spin_lock(&ctx->slock); |
| @@ -1278,963 +400,234 @@ static irqreturn_t cal_irq(int irq_cal, void *data) · 9 unmodified lines | |||
| 1278 | return IRQ_HANDLED; | 400 | return IRQ_HANDLED; |
| 1279 | } | 401 | } |
| 1280 | 402 | ||
| 1281 | /* | 403 | /* ------------------------------------------------------------------ |
| 1282 | * video ioctls | 404 | * Asynchronous V4L2 subdev binding |
| 405 | * ------------------------------------------------------------------ | ||
| 1283 | */ | 406 | */ |
| 1284 | static int cal_querycap(struct file *file, void *priv, | ||
| 1285 | struct v4l2_capability *cap) | ||
| 1286 | { | ||
| 1287 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1288 | 407 | ||
| 1289 | strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); | 408 | struct cal_v4l2_async_subdev { |
| 1290 | strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); | 409 | struct v4l2_async_subdev asd; |
| 410 | struct cal_camerarx *phy; | ||
| 411 | }; | ||
| 1291 | 412 | ||
| 1292 | snprintf(cap->bus_info, sizeof(cap->bus_info), | 413 | static inline struct cal_v4l2_async_subdev * |
| 1293 | "platform:%s", ctx->v4l2_dev.name); | 414 | to_cal_asd(struct v4l2_async_subdev *asd) |
| 1294 | return 0; | 415 | { |
| 416 | return container_of(asd, struct cal_v4l2_async_subdev, asd); | ||
| 1295 | } | 417 | } |
| 1296 | 418 | ||
| 1297 | static int cal_enum_fmt_vid_cap(struct file *file, void *priv, | 419 | static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, |
| 1298 | struct v4l2_fmtdesc *f) | 420 | struct v4l2_subdev *subdev, |
| 421 | struct v4l2_async_subdev *asd) | ||
| 1299 | { | 422 | { |
| 1300 | struct cal_ctx *ctx = video_drvdata(file); | 423 | struct cal_camerarx *phy = to_cal_asd(asd)->phy; |
| 1301 | const struct cal_fmt *fmt = NULL; | ||
| 1302 | |||
| 1303 | if (f->index >= ctx->num_active_fmt) | ||
| 1304 | return -EINVAL; | ||
| 1305 | |||
| 1306 | fmt = ctx->active_fmt[f->index]; | ||
| 1307 | 424 | ||
| 1308 | f->pixelformat = fmt->fourcc; | 425 | if (phy->sensor) { |
| 1309 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 426 | phy_info(phy, "Rejecting subdev %s (Already set!!)", |
| 1310 | return 0; | 427 | subdev->name); |
| 1311 | } | 428 | return 0; |
| 1312 | |||
| 1313 | static int __subdev_get_format(struct cal_ctx *ctx, | ||
| 1314 | struct v4l2_mbus_framefmt *fmt) | ||
| 1315 | { | ||
| 1316 | struct v4l2_subdev_format sd_fmt; | ||
| 1317 | struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; | ||
| 1318 | int ret; | ||
| 1319 | |||
| 1320 | sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 1321 | sd_fmt.pad = 0; | ||
| 1322 | |||
| 1323 | ret = v4l2_subdev_call(ctx->sensor, pad, get_fmt, NULL, &sd_fmt); | ||
| 1324 | if (ret) | ||
| 1325 | return ret; | ||
| 1326 | |||
| 1327 | *fmt = *mbus_fmt; | ||
| 1328 | |||
| 1329 | ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, | ||
| 1330 | fmt->width, fmt->height, fmt->code); | ||
| 1331 | |||
| 1332 | return 0; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | static int __subdev_set_format(struct cal_ctx *ctx, | ||
| 1336 | struct v4l2_mbus_framefmt *fmt) | ||
| 1337 | { | ||
| 1338 | struct v4l2_subdev_format sd_fmt; | ||
| 1339 | struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; | ||
| 1340 | int ret; | ||
| 1341 | |||
| 1342 | sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 1343 | sd_fmt.pad = 0; | ||
| 1344 | *mbus_fmt = *fmt; | ||
| 1345 | |||
| 1346 | ret = v4l2_subdev_call(ctx->sensor, pad, set_fmt, NULL, &sd_fmt); | ||
| 1347 | if (ret) | ||
| 1348 | return ret; | ||
| 1349 | |||
| 1350 | ctx_dbg(1, ctx, "%s %dx%d code:%04X\n", __func__, | ||
| 1351 | fmt->width, fmt->height, fmt->code); | ||
| 1352 | |||
| 1353 | return 0; | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | static int cal_calc_format_size(struct cal_ctx *ctx, | ||
| 1357 | const struct cal_fmt *fmt, | ||
| 1358 | struct v4l2_format *f) | ||
| 1359 | { | ||
| 1360 | u32 bpl, max_width; | ||
| 1361 | |||
| 1362 | if (!fmt) { | ||
| 1363 | ctx_dbg(3, ctx, "No cal_fmt provided!\n"); | ||
| 1364 | return -EINVAL; | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | /* | ||
| 1368 | * Maximum width is bound by the DMA max width in bytes. | ||
| 1369 | * We need to recalculate the actual maxi width depending on the | ||
| 1370 | * number of bytes per pixels required. | ||
| 1371 | */ | ||
| 1372 | max_width = MAX_WIDTH_BYTES / (ALIGN(fmt->bpp, 8) >> 3); | ||
| 1373 | v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2, | ||
| 1374 | &f->fmt.pix.height, 32, MAX_HEIGHT_LINES, 0, 0); | ||
| 1375 | |||
| 1376 | bpl = (f->fmt.pix.width * ALIGN(fmt->bpp, 8)) >> 3; | ||
| 1377 | f->fmt.pix.bytesperline = ALIGN(bpl, 16); | ||
| 1378 | |||
| 1379 | f->fmt.pix.sizeimage = f->fmt.pix.height * | ||
| 1380 | f->fmt.pix.bytesperline; | ||
| 1381 | |||
| 1382 | ctx_dbg(3, ctx, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n", | ||
| 1383 | __func__, fourcc_to_str(f->fmt.pix.pixelformat), | ||
| 1384 | f->fmt.pix.width, f->fmt.pix.height, | ||
| 1385 | f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); | ||
| 1386 | |||
| 1387 | return 0; | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | static int cal_g_fmt_vid_cap(struct file *file, void *priv, | ||
| 1391 | struct v4l2_format *f) | ||
| 1392 | { | ||
| 1393 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1394 | |||
| 1395 | *f = ctx->v_fmt; | ||
| 1396 | |||
| 1397 | return 0; | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | static int cal_try_fmt_vid_cap(struct file *file, void *priv, | ||
| 1401 | struct v4l2_format *f) | ||
| 1402 | { | ||
| 1403 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1404 | const struct cal_fmt *fmt; | ||
| 1405 | struct v4l2_subdev_frame_size_enum fse; | ||
| 1406 | int ret, found; | ||
| 1407 | |||
| 1408 | fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat); | ||
| 1409 | if (!fmt) { | ||
| 1410 | ctx_dbg(3, ctx, "Fourcc format (0x%08x) not found.\n", | ||
| 1411 | f->fmt.pix.pixelformat); | ||
| 1412 | |||
| 1413 | /* Just get the first one enumerated */ | ||
| 1414 | fmt = ctx->active_fmt[0]; | ||
| 1415 | f->fmt.pix.pixelformat = fmt->fourcc; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | f->fmt.pix.field = ctx->v_fmt.fmt.pix.field; | ||
| 1419 | |||
| 1420 | /* check for/find a valid width/height */ | ||
| 1421 | ret = 0; | ||
| 1422 | found = false; | ||
| 1423 | fse.pad = 0; | ||
| 1424 | fse.code = fmt->code; | ||
| 1425 | fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 1426 | for (fse.index = 0; ; fse.index++) { | ||
| 1427 | ret = v4l2_subdev_call(ctx->sensor, pad, enum_frame_size, | ||
| 1428 | NULL, &fse); | ||
| 1429 | if (ret) | ||
| 1430 | break; | ||
| 1431 | |||
| 1432 | if ((f->fmt.pix.width == fse.max_width) && | ||
| 1433 | (f->fmt.pix.height == fse.max_height)) { | ||
| 1434 | found = true; | ||
| 1435 | break; | ||
| 1436 | } else if ((f->fmt.pix.width >= fse.min_width) && | ||
| 1437 | (f->fmt.pix.width <= fse.max_width) && | ||
| 1438 | (f->fmt.pix.height >= fse.min_height) && | ||
| 1439 | (f->fmt.pix.height <= fse.max_height)) { | ||
| 1440 | found = true; | ||
| 1441 | break; | ||
| 1442 | } | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | if (!found) { | ||
| 1446 | /* use existing values as default */ | ||
| 1447 | f->fmt.pix.width = ctx->v_fmt.fmt.pix.width; | ||
| 1448 | f->fmt.pix.height = ctx->v_fmt.fmt.pix.height; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | /* | ||
| 1452 | * Use current colorspace for now, it will get | ||
| 1453 | * updated properly during s_fmt | ||
| 1454 | */ | ||
| 1455 | f->fmt.pix.colorspace = ctx->v_fmt.fmt.pix.colorspace; | ||
| 1456 | return cal_calc_format_size(ctx, fmt, f); | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | static int cal_s_fmt_vid_cap(struct file *file, void *priv, | ||
| 1460 | struct v4l2_format *f) | ||
| 1461 | { | ||
| 1462 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1463 | struct vb2_queue *q = &ctx->vb_vidq; | ||
| 1464 | const struct cal_fmt *fmt; | ||
| 1465 | struct v4l2_mbus_framefmt mbus_fmt; | ||
| 1466 | int ret; | ||
| 1467 | |||
| 1468 | if (vb2_is_busy(q)) { | ||
| 1469 | ctx_dbg(3, ctx, "%s device busy\n", __func__); | ||
| 1470 | return -EBUSY; | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | ret = cal_try_fmt_vid_cap(file, priv, f); | ||
| 1474 | if (ret < 0) | ||
| 1475 | return ret; | ||
| 1476 | |||
| 1477 | fmt = find_format_by_pix(ctx, f->fmt.pix.pixelformat); | ||
| 1478 | |||
| 1479 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, fmt->code); | ||
| 1480 | |||
| 1481 | ret = __subdev_set_format(ctx, &mbus_fmt); | ||
| 1482 | if (ret) | ||
| 1483 | return ret; | ||
| 1484 | |||
| 1485 | /* Just double check nothing has gone wrong */ | ||
| 1486 | if (mbus_fmt.code != fmt->code) { | ||
| 1487 | ctx_dbg(3, ctx, | ||
| 1488 | "%s subdev changed format on us, this should not happen\n", | ||
| 1489 | __func__); | ||
| 1490 | return -EINVAL; | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt); | ||
| 1494 | ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1495 | ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc; | ||
| 1496 | cal_calc_format_size(ctx, fmt, &ctx->v_fmt); | ||
| 1497 | ctx->fmt = fmt; | ||
| 1498 | ctx->m_fmt = mbus_fmt; | ||
| 1499 | *f = ctx->v_fmt; | ||
| 1500 | |||
| 1501 | return 0; | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | static int cal_enum_framesizes(struct file *file, void *fh, | ||
| 1505 | struct v4l2_frmsizeenum *fsize) | ||
| 1506 | { | ||
| 1507 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1508 | const struct cal_fmt *fmt; | ||
| 1509 | struct v4l2_subdev_frame_size_enum fse; | ||
| 1510 | int ret; | ||
| 1511 | |||
| 1512 | /* check for valid format */ | ||
| 1513 | fmt = find_format_by_pix(ctx, fsize->pixel_format); | ||
| 1514 | if (!fmt) { | ||
| 1515 | ctx_dbg(3, ctx, "Invalid pixel code: %x\n", | ||
| 1516 | fsize->pixel_format); | ||
| 1517 | return -EINVAL; | ||
| 1518 | } | 429 | } |
| 1519 | 430 | ||
| 1520 | fse.index = fsize->index; | 431 | phy->sensor = subdev; |
| 1521 | fse.pad = 0; | 432 | phy_dbg(1, phy, "Using sensor %s for capture\n", subdev->name); |
| 1522 | fse.code = fmt->code; | ||
| 1523 | fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 1524 | |||
| 1525 | ret = v4l2_subdev_call(ctx->sensor, pad, enum_frame_size, NULL, &fse); | ||
| 1526 | if (ret) | ||
| 1527 | return ret; | ||
| 1528 | |||
| 1529 | ctx_dbg(1, ctx, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", | ||
| 1530 | __func__, fse.index, fse.code, fse.min_width, fse.max_width, | ||
| 1531 | fse.min_height, fse.max_height); | ||
| 1532 | |||
| 1533 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
| 1534 | fsize->discrete.width = fse.max_width; | ||
| 1535 | fsize->discrete.height = fse.max_height; | ||
| 1536 | |||
| 1537 | return 0; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | static int cal_enum_input(struct file *file, void *priv, | ||
| 1541 | struct v4l2_input *inp) | ||
| 1542 | { | ||
| 1543 | if (inp->index >= CAL_NUM_INPUT) | ||
| 1544 | return -EINVAL; | ||
| 1545 | |||
| 1546 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
| 1547 | sprintf(inp->name, "Camera %u", inp->index); | ||
| 1548 | return 0; | ||
| 1549 | } | ||
| 1550 | |||
| 1551 | static int cal_g_input(struct file *file, void *priv, unsigned int *i) | ||
| 1552 | { | ||
| 1553 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1554 | |||
| 1555 | *i = ctx->input; | ||
| 1556 | return 0; | ||
| 1557 | } | ||
| 1558 | |||
| 1559 | static int cal_s_input(struct file *file, void *priv, unsigned int i) | ||
| 1560 | { | ||
| 1561 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1562 | |||
| 1563 | if (i >= CAL_NUM_INPUT) | ||
| 1564 | return -EINVAL; | ||
| 1565 | |||
| 1566 | ctx->input = i; | ||
| 1567 | return 0; | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | /* timeperframe is arbitrary and continuous */ | ||
| 1571 | static int cal_enum_frameintervals(struct file *file, void *priv, | ||
| 1572 | struct v4l2_frmivalenum *fival) | ||
| 1573 | { | ||
| 1574 | struct cal_ctx *ctx = video_drvdata(file); | ||
| 1575 | const struct cal_fmt *fmt; | ||
| 1576 | struct v4l2_subdev_frame_interval_enum fie = { | ||
| 1577 | .index = fival->index, | ||
| 1578 | .width = fival->width, | ||
| 1579 | .height = fival->height, | ||
| 1580 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
| 1581 | }; | ||
| 1582 | int ret; | ||
| 1583 | |||
| 1584 | fmt = find_format_by_pix(ctx, fival->pixel_format); | ||
| 1585 | if (!fmt) | ||
| 1586 | return -EINVAL; | ||
| 1587 | |||
| 1588 | fie.code = fmt->code; | ||
| 1589 | ret = v4l2_subdev_call(ctx->sensor, pad, enum_frame_interval, | ||
| 1590 | NULL, &fie); | ||
| 1591 | if (ret) | ||
| 1592 | return ret; | ||
| 1593 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
| 1594 | fival->discrete = fie.interval; | ||
| 1595 | 433 | ||
| 1596 | return 0; | 434 | return 0; |
| 1597 | } | 435 | } |
| 1598 | 436 | ||
| 1599 | /* | 437 | static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) |
| 1600 | * Videobuf operations | ||
| 1601 | */ | ||
| 1602 | static int cal_queue_setup(struct vb2_queue *vq, | ||
| 1603 | unsigned int *nbuffers, unsigned int *nplanes, | ||
| 1604 | unsigned int sizes[], struct device *alloc_devs[]) | ||
| 1605 | { | 438 | { |
| 1606 | struct cal_ctx *ctx = vb2_get_drv_priv(vq); | 439 | struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier); |
| 1607 | unsigned size = ctx->v_fmt.fmt.pix.sizeimage; | 440 | unsigned int i; |
| 1608 | |||
| 1609 | if (vq->num_buffers + *nbuffers < 3) | ||
| 1610 | *nbuffers = 3 - vq->num_buffers; | ||
| 1611 | |||
| 1612 | if (*nplanes) { | ||
| 1613 | if (sizes[0] < size) | ||
| 1614 | return -EINVAL; | ||
| 1615 | size = sizes[0]; | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | *nplanes = 1; | ||
| 1619 | sizes[0] = size; | ||
| 1620 | |||
| 1621 | ctx_dbg(3, ctx, "nbuffers=%d, size=%d\n", *nbuffers, sizes[0]); | ||
| 1622 | |||
| 1623 | return 0; | ||
| 1624 | } | ||
| 1625 | 441 | ||
| 1626 | static int cal_buffer_prepare(struct vb2_buffer *vb) | 442 | for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { |
| 1627 | { | 443 | if (cal->ctx[i]) |
| 1628 | struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | 444 | cal_ctx_v4l2_register(cal->ctx[i]); |
| 1629 | struct cal_buffer *buf = container_of(vb, struct cal_buffer, | ||
| 1630 | vb.vb2_buf); | ||
| 1631 | unsigned long size; | ||
| 1632 | |||
| 1633 | if (WARN_ON(!ctx->fmt)) | ||
| 1634 | return -EINVAL; | ||
| 1635 | |||
| 1636 | size = ctx->v_fmt.fmt.pix.sizeimage; | ||
| 1637 | if (vb2_plane_size(vb, 0) < size) { | ||
| 1638 | ctx_err(ctx, | ||
| 1639 | "data will not fit into plane (%lu < %lu)\n", | ||
| 1640 | vb2_plane_size(vb, 0), size); | ||
| 1641 | return -EINVAL; | ||
| 1642 | } | 445 | } |
| 1643 | 446 | ||
| 1644 | vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); | ||
| 1645 | return 0; | 447 | return 0; |
| 1646 | } | 448 | } |
| 1647 | 449 | ||
| 1648 | static void cal_buffer_queue(struct vb2_buffer *vb) | 450 | static const struct v4l2_async_notifier_operations cal_async_notifier_ops = { |
| 1649 | { | 451 | .bound = cal_async_notifier_bound, |
| 1650 | struct cal_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | 452 | .complete = cal_async_notifier_complete, |
| 1651 | struct cal_buffer *buf = container_of(vb, struct cal_buffer, | 453 | }; |
| 1652 | vb.vb2_buf); | ||
| 1653 | struct cal_dmaqueue *vidq = &ctx->vidq; | ||
| 1654 | unsigned long flags = 0; | ||
| 1655 | |||
| 1656 | /* recheck locking */ | ||
| 1657 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 1658 | list_add_tail(&buf->list, &vidq->active); | ||
| 1659 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 1660 | } | ||
| 1661 | 454 | ||
| 1662 | static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) | 455 | static int cal_async_notifier_register(struct cal_dev *cal) |
| 1663 | { | 456 | { |
| 1664 | struct cal_ctx *ctx = vb2_get_drv_priv(vq); | 457 | unsigned int i; |
| 1665 | struct cal_dmaqueue *dma_q = &ctx->vidq; | ||
| 1666 | struct cal_buffer *buf, *tmp; | ||
| 1667 | unsigned long addr = 0; | ||
| 1668 | unsigned long flags; | ||
| 1669 | int ret; | 458 | int ret; |
| 1670 | 459 | ||
| 1671 | spin_lock_irqsave(&ctx->slock, flags); | 460 | v4l2_async_notifier_init(&cal->notifier); |
| 1672 | if (list_empty(&dma_q->active)) { | 461 | cal->notifier.ops = &cal_async_notifier_ops; |
| 1673 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 1674 | ctx_dbg(3, ctx, "buffer queue is empty\n"); | ||
| 1675 | return -EIO; | ||
| 1676 | } | ||
| 1677 | 462 | ||
| 1678 | buf = list_entry(dma_q->active.next, struct cal_buffer, list); | 463 | for (i = 0; i < ARRAY_SIZE(cal->phy); ++i) { |
| 1679 | ctx->cur_frm = buf; | 464 | struct cal_camerarx *phy = cal->phy[i]; |
| 1680 | ctx->next_frm = buf; | 465 | struct cal_v4l2_async_subdev *casd; |
| 1681 | list_del(&buf->list); | 466 | struct v4l2_async_subdev *asd; |
| 1682 | spin_unlock_irqrestore(&ctx->slock, flags); | 467 | struct fwnode_handle *fwnode; |
| 1683 | 468 | ||
| 1684 | addr = vb2_dma_contig_plane_dma_addr(&ctx->cur_frm->vb.vb2_buf, 0); | 469 | if (!phy || !phy->sensor_node) |
| 1685 | ctx->sequence = 0; | 470 | continue; |
| 1686 | 471 | ||
| 1687 | ret = cal_get_external_info(ctx); | 472 | fwnode = of_fwnode_handle(phy->sensor_node); |
| 1688 | if (ret < 0) | 473 | asd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier, |
| 1689 | goto err; | 474 | fwnode, |
| 475 | sizeof(*asd)); | ||
| 476 | if (IS_ERR(asd)) { | ||
| 477 | phy_err(phy, "Failed to add subdev to notifier\n"); | ||
| 478 | ret = PTR_ERR(asd); | ||
| 479 | goto error; | ||
| 480 | } | ||
| 1690 | 481 | ||
| 1691 | ret = v4l2_subdev_call(ctx->sensor, core, s_power, 1); | 482 | casd = to_cal_asd(asd); |
| 1692 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { | 483 | casd->phy = phy; |
| 1693 | ctx_err(ctx, "power on failed in subdev\n"); | ||
| 1694 | goto err; | ||
| 1695 | } | 484 | } |
| 1696 | 485 | ||
| 1697 | pm_runtime_get_sync(&ctx->dev->pdev->dev); | 486 | ret = v4l2_async_notifier_register(&cal->v4l2_dev, &cal->notifier); |
| 1698 | |||
| 1699 | csi2_ctx_config(ctx); | ||
| 1700 | pix_proc_config(ctx); | ||
| 1701 | cal_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline, | ||
| 1702 | ctx->v_fmt.fmt.pix.height); | ||
| 1703 | csi2_lane_config(ctx); | ||
| 1704 | |||
| 1705 | enable_irqs(ctx); | ||
| 1706 | csi2_phy_init(ctx); | ||
| 1707 | |||
| 1708 | ret = v4l2_subdev_call(ctx->sensor, video, s_stream, 1); | ||
| 1709 | if (ret) { | 487 | if (ret) { |
| 1710 | v4l2_subdev_call(ctx->sensor, core, s_power, 0); | 488 | cal_err(cal, "Error registering async notifier\n"); |
| 1711 | ctx_err(ctx, "stream on failed in subdev\n"); | 489 | goto error; |
| 1712 | pm_runtime_put_sync(&ctx->dev->pdev->dev); | ||
| 1713 | goto err; | ||
| 1714 | } | 490 | } |
| 1715 | 491 | ||
| 1716 | csi2_wait_for_phy(ctx); | ||
| 1717 | cal_wr_dma_addr(ctx, addr); | ||
| 1718 | csi2_ppi_enable(ctx); | ||
| 1719 | |||
| 1720 | if (debug >= 4) | ||
| 1721 | cal_quickdump_regs(ctx->dev); | ||
| 1722 | |||
| 1723 | return 0; | 492 | return 0; |
| 1724 | 493 | ||
| 1725 | err: | 494 | error: |
| 1726 | spin_lock_irqsave(&ctx->slock, flags); | 495 | v4l2_async_notifier_cleanup(&cal->notifier); |
| 1727 | vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
| 1728 | ctx->cur_frm = NULL; | ||
| 1729 | ctx->next_frm = NULL; | ||
| 1730 | list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { | ||
| 1731 | list_del(&buf->list); | ||
| 1732 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
| 1733 | } | ||
| 1734 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 1735 | return ret; | 496 | return ret; |
| 1736 | } | 497 | } |
| 1737 | 498 | ||
| 1738 | static void cal_stop_streaming(struct vb2_queue *vq) | 499 | static void cal_async_notifier_unregister(struct cal_dev *cal) |
| 1739 | { | 500 | { |
| 1740 | struct cal_ctx *ctx = vb2_get_drv_priv(vq); | 501 | v4l2_async_notifier_unregister(&cal->notifier); |
| 1741 | struct cal_dmaqueue *dma_q = &ctx->vidq; | 502 | v4l2_async_notifier_cleanup(&cal->notifier); |
| 1742 | struct cal_buffer *buf, *tmp; | ||
| 1743 | unsigned long timeout; | ||
| 1744 | unsigned long flags; | ||
| 1745 | int ret; | ||
| 1746 | bool dma_act; | ||
| 1747 | |||
| 1748 | csi2_ppi_disable(ctx); | ||
| 1749 | |||
| 1750 | /* wait for stream and dma to finish */ | ||
| 1751 | dma_act = true; | ||
| 1752 | timeout = jiffies + msecs_to_jiffies(500); | ||
| 1753 | while (dma_act && time_before(jiffies, timeout)) { | ||
| 1754 | msleep(50); | ||
| 1755 | |||
| 1756 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 1757 | dma_act = ctx->dma_act; | ||
| 1758 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 1759 | } | ||
| 1760 | |||
| 1761 | if (dma_act) | ||
| 1762 | ctx_err(ctx, "failed to disable dma cleanly\n"); | ||
| 1763 | |||
| 1764 | disable_irqs(ctx); | ||
| 1765 | csi2_phy_deinit(ctx); | ||
| 1766 | |||
| 1767 | if (v4l2_subdev_call(ctx->sensor, video, s_stream, 0)) | ||
| 1768 | ctx_err(ctx, "stream off failed in subdev\n"); | ||
| 1769 | |||
| 1770 | ret = v4l2_subdev_call(ctx->sensor, core, s_power, 0); | ||
| 1771 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
| 1772 | ctx_err(ctx, "power off failed in subdev\n"); | ||
| 1773 | |||
| 1774 | /* Release all active buffers */ | ||
| 1775 | spin_lock_irqsave(&ctx->slock, flags); | ||
| 1776 | list_for_each_entry_safe(buf, tmp, &dma_q->active, list) { | ||
| 1777 | list_del(&buf->list); | ||
| 1778 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
| 1779 | } | ||
| 1780 | |||
| 1781 | if (ctx->cur_frm == ctx->next_frm) { | ||
| 1782 | vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
| 1783 | } else { | ||
| 1784 | vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
| 1785 | vb2_buffer_done(&ctx->next_frm->vb.vb2_buf, | ||
| 1786 | VB2_BUF_STATE_ERROR); | ||
| 1787 | } | ||
| 1788 | ctx->cur_frm = NULL; | ||
| 1789 | ctx->next_frm = NULL; | ||
| 1790 | spin_unlock_irqrestore(&ctx->slock, flags); | ||
| 1791 | |||
| 1792 | pm_runtime_put_sync(&ctx->dev->pdev->dev); | ||
| 1793 | } | 503 | } |
| 1794 | 504 | ||
| 1795 | static const struct vb2_ops cal_video_qops = { | 505 | /* ------------------------------------------------------------------ |
| 1796 | .queue_setup = cal_queue_setup, | 506 | * Media and V4L2 device handling |
| 1797 | .buf_prepare = cal_buffer_prepare, | ||
| 1798 | .buf_queue = cal_buffer_queue, | ||
| 1799 | .start_streaming = cal_start_streaming, | ||
| 1800 | .stop_streaming = cal_stop_streaming, | ||
| 1801 | .wait_prepare = vb2_ops_wait_prepare, | ||
| 1802 | .wait_finish = vb2_ops_wait_finish, | ||
| 1803 | }; | ||
| 1804 | |||
| 1805 | static const struct v4l2_file_operations cal_fops = { | ||
| 1806 | .owner = THIS_MODULE, | ||
| 1807 | .open = v4l2_fh_open, | ||
| 1808 | .release = vb2_fop_release, | ||
| 1809 | .read = vb2_fop_read, | ||
| 1810 | .poll = vb2_fop_poll, | ||
| 1811 | .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ | ||
| 1812 | .mmap = vb2_fop_mmap, | ||
| 1813 | }; | ||
| 1814 | |||
| 1815 | static const struct v4l2_ioctl_ops cal_ioctl_ops = { | ||
| 1816 | .vidioc_querycap = cal_querycap, | ||
| 1817 | .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap, | ||
| 1818 | .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, | ||
| 1819 | .vidioc_try_fmt_vid_cap = cal_try_fmt_vid_cap, | ||
| 1820 | .vidioc_s_fmt_vid_cap = cal_s_fmt_vid_cap, | ||
| 1821 | .vidioc_enum_framesizes = cal_enum_framesizes, | ||
| 1822 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
| 1823 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
| 1824 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
| 1825 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
| 1826 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
| 1827 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
| 1828 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
| 1829 | .vidioc_enum_input = cal_enum_input, | ||
| 1830 | .vidioc_g_input = cal_g_input, | ||
| 1831 | .vidioc_s_input = cal_s_input, | ||
| 1832 | .vidioc_enum_frameintervals = cal_enum_frameintervals, | ||
| 1833 | .vidioc_streamon = vb2_ioctl_streamon, | ||
| 1834 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
| 1835 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
| 1836 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
| 1837 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
| 1838 | }; | ||
| 1839 | |||
| 1840 | static const struct video_device cal_videodev = { | ||
| 1841 | .name = CAL_MODULE_NAME, | ||
| 1842 | .fops = &cal_fops, | ||
| 1843 | .ioctl_ops = &cal_ioctl_ops, | ||
| 1844 | .minor = -1, | ||
| 1845 | .release = video_device_release_empty, | ||
| 1846 | .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | ||
| 1847 | V4L2_CAP_READWRITE, | ||
| 1848 | }; | ||
| 1849 | |||
| 1850 | /* ----------------------------------------------------------------- | ||
| 1851 | * Initialization and module stuff | ||
| 1852 | * ------------------------------------------------------------------ | 507 | * ------------------------------------------------------------------ |
| 1853 | */ | 508 | */ |
| 1854 | static int cal_complete_ctx(struct cal_ctx *ctx); | ||
| 1855 | 509 | ||
| 1856 | static int cal_async_bound(struct v4l2_async_notifier *notifier, | 510 | /* |
| 1857 | struct v4l2_subdev *subdev, | 511 | * Register user-facing devices. To be called at the end of the probe function |
| 1858 | struct v4l2_async_subdev *asd) | 512 | * when all resources are initialized and ready. |
| 513 | */ | ||
| 514 | static int cal_media_register(struct cal_dev *cal) | ||
| 1859 | { | 515 | { |
| 1860 | struct cal_ctx *ctx = notifier_to_ctx(notifier); | 516 | int ret; |
| 1861 | struct v4l2_subdev_mbus_code_enum mbus_code; | ||
| 1862 | int ret = 0; | ||
| 1863 | int i, j, k; | ||
| 1864 | |||
| 1865 | if (ctx->sensor) { | ||
| 1866 | ctx_info(ctx, "Rejecting subdev %s (Already set!!)", | ||
| 1867 | subdev->name); | ||
| 1868 | return 0; | ||
| 1869 | } | ||
| 1870 | |||
| 1871 | ctx->sensor = subdev; | ||
| 1872 | ctx_dbg(1, ctx, "Using sensor %s for capture\n", subdev->name); | ||
| 1873 | |||
| 1874 | /* Enumerate sub device formats and enable all matching local formats */ | ||
| 1875 | ctx->num_active_fmt = 0; | ||
| 1876 | for (j = 0, i = 0; ret != -EINVAL; ++j) { | ||
| 1877 | struct cal_fmt *fmt; | ||
| 1878 | |||
| 1879 | memset(&mbus_code, 0, sizeof(mbus_code)); | ||
| 1880 | mbus_code.index = j; | ||
| 1881 | mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
| 1882 | ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, | ||
| 1883 | NULL, &mbus_code); | ||
| 1884 | if (ret) | ||
| 1885 | continue; | ||
| 1886 | |||
| 1887 | ctx_dbg(2, ctx, | ||
| 1888 | "subdev %s: code: %04x idx: %d\n", | ||
| 1889 | subdev->name, mbus_code.code, j); | ||
| 1890 | |||
| 1891 | for (k = 0; k < ARRAY_SIZE(cal_formats); k++) { | ||
| 1892 | fmt = &cal_formats[k]; | ||
| 1893 | 517 | ||
| 1894 | if (mbus_code.code == fmt->code) { | 518 | ret = media_device_register(&cal->mdev); |
| 1895 | ctx->active_fmt[i] = fmt; | 519 | if (ret) { |
| 1896 | ctx_dbg(2, ctx, | 520 | cal_err(cal, "Failed to register media device\n"); |
| 1897 | "matched fourcc: %s: code: %04x idx: %d\n", | 521 | return ret; |
| 1898 | fourcc_to_str(fmt->fourcc), | ||
| 1899 | fmt->code, i); | ||
| 1900 | ctx->num_active_fmt = ++i; | ||
| 1901 | } | ||
| 1902 | } | ||
| 1903 | } | 522 | } |
| 1904 | 523 | ||
| 1905 | if (i == 0) { | 524 | /* |
| 1906 | ctx_err(ctx, "No suitable format reported by subdev %s\n", | 525 | * Register the async notifier. This may trigger registration of the |
| 1907 | subdev->name); | 526 | * V4L2 video devices if all subdevs are ready. |
| 1908 | return -EINVAL; | 527 | */ |
| 528 | ret = cal_async_notifier_register(cal); | ||
| 529 | if (ret) { | ||
| 530 | media_device_unregister(&cal->mdev); | ||
| 531 | return ret; | ||
| 1909 | } | 532 | } |
| 1910 | 533 | ||
| 1911 | cal_complete_ctx(ctx); | ||
| 1912 | |||
| 1913 | return 0; | 534 | return 0; |
| 1914 | } | 535 | } |
| 1915 | 536 | ||
| 1916 | static int cal_async_complete(struct v4l2_async_notifier *notifier) | 537 | /* |
| 538 | * Unregister the user-facing devices, but don't free memory yet. To be called | ||
| 539 | * at the beginning of the remove function, to disallow access from userspace. | ||
| 540 | */ | ||
| 541 | static void cal_media_unregister(struct cal_dev *cal) | ||
| 1917 | { | 542 | { |
| 1918 | struct cal_ctx *ctx = notifier_to_ctx(notifier); | 543 | unsigned int i; |
| 1919 | const struct cal_fmt *fmt; | ||
| 1920 | struct v4l2_mbus_framefmt mbus_fmt; | ||
| 1921 | int ret; | ||
| 1922 | |||
| 1923 | ret = __subdev_get_format(ctx, &mbus_fmt); | ||
| 1924 | if (ret) | ||
| 1925 | return ret; | ||
| 1926 | 544 | ||
| 1927 | fmt = find_format_by_code(ctx, mbus_fmt.code); | 545 | /* Unregister all the V4L2 video devices. */ |
| 1928 | if (!fmt) { | 546 | for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { |
| 1929 | ctx_dbg(3, ctx, "mbus code format (0x%08x) not found.\n", | 547 | if (cal->ctx[i]) |
| 1930 | mbus_fmt.code); | 548 | cal_ctx_v4l2_unregister(cal->ctx[i]); |
| 1931 | return -EINVAL; | ||
| 1932 | } | 549 | } |
| 1933 | 550 | ||
| 1934 | /* Save current subdev format */ | 551 | cal_async_notifier_unregister(cal); |
| 1935 | v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt); | 552 | media_device_unregister(&cal->mdev); |
| 1936 | ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1937 | ctx->v_fmt.fmt.pix.pixelformat = fmt->fourcc; | ||
| 1938 | cal_calc_format_size(ctx, fmt, &ctx->v_fmt); | ||
| 1939 | ctx->fmt = fmt; | ||
| 1940 | ctx->m_fmt = mbus_fmt; | ||
| 1941 | |||
| 1942 | return 0; | ||
| 1943 | } | 553 | } |
| 1944 | 554 | ||
| 1945 | static const struct v4l2_async_notifier_operations cal_async_ops = { | 555 | /* |
| 1946 | .bound = cal_async_bound, | 556 | * Initialize the in-kernel objects. To be called at the beginning of the probe |
| 1947 | .complete = cal_async_complete, | 557 | * function, before the V4L2 device is used by the driver. |
| 1948 | }; | 558 | */ |
| 1949 | 559 | static int cal_media_init(struct cal_dev *cal) | |
| 1950 | static int cal_complete_ctx(struct cal_ctx *ctx) | ||
| 1951 | { | 560 | { |
| 1952 | struct video_device *vfd; | 561 | struct media_device *mdev = &cal->mdev; |
| 1953 | struct vb2_queue *q; | ||
| 1954 | int ret; | 562 | int ret; |
| 1955 | 563 | ||
| 1956 | ctx->timeperframe = tpf_default; | 564 | mdev->dev = cal->dev; |
| 1957 | ctx->external_rate = 192000000; | 565 | mdev->hw_revision = cal->revision; |
| 1958 | 566 | strscpy(mdev->model, "CAL", sizeof(mdev->model)); | |
| 1959 | /* initialize locks */ | 567 | snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", |
| 1960 | spin_lock_init(&ctx->slock); | 568 | dev_name(mdev->dev)); |
| 1961 | mutex_init(&ctx->mutex); | 569 | media_device_init(mdev); |
| 1962 | |||
| 1963 | /* initialize queue */ | ||
| 1964 | q = &ctx->vb_vidq; | ||
| 1965 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
| 1966 | q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; | ||
| 1967 | q->drv_priv = ctx; | ||
| 1968 | q->buf_struct_size = sizeof(struct cal_buffer); | ||
| 1969 | q->ops = &cal_video_qops; | ||
| 1970 | q->mem_ops = &vb2_dma_contig_memops; | ||
| 1971 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
| 1972 | q->lock = &ctx->mutex; | ||
| 1973 | q->min_buffers_needed = 3; | ||
| 1974 | q->dev = ctx->v4l2_dev.dev; | ||
| 1975 | |||
| 1976 | ret = vb2_queue_init(q); | ||
| 1977 | if (ret) | ||
| 1978 | return ret; | ||
| 1979 | |||
| 1980 | /* init video dma queues */ | ||
| 1981 | INIT_LIST_HEAD(&ctx->vidq.active); | ||
| 1982 | |||
| 1983 | vfd = &ctx->vdev; | ||
| 1984 | *vfd = cal_videodev; | ||
| 1985 | vfd->v4l2_dev = &ctx->v4l2_dev; | ||
| 1986 | vfd->queue = q; | ||
| 1987 | 570 | ||
| 1988 | /* | 571 | /* |
| 1989 | * Provide a mutex to v4l2 core. It will be used to protect | 572 | * Initialize the V4L2 device (despite the function name, this performs |
| 1990 | * all fops and v4l2 ioctls. | 573 | * initialization, not registration). |
| 1991 | */ | 574 | */ |
| 1992 | vfd->lock = &ctx->mutex; | 575 | cal->v4l2_dev.mdev = mdev; |
| 1993 | video_set_drvdata(vfd, ctx); | 576 | ret = v4l2_device_register(cal->dev, &cal->v4l2_dev); |
| 1994 | 577 | if (ret) { | |
| 1995 | ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr); | 578 | cal_err(cal, "Failed to register V4L2 device\n"); |
| 1996 | if (ret < 0) | ||
| 1997 | return ret; | 579 | return ret; |
| 580 | } | ||
| 1998 | 581 | ||
| 1999 | v4l2_info(&ctx->v4l2_dev, "V4L2 device registered as %s\n", | 582 | vb2_dma_contig_set_max_seg_size(cal->dev, DMA_BIT_MASK(32)); |
| 2000 | video_device_node_name(vfd)); | ||
| 2001 | 583 | ||
| 2002 | return 0; | 584 | return 0; |
| 2003 | } | 585 | } |
| 2004 | 586 | ||
| 2005 | static struct device_node * | 587 | /* |
| 2006 | of_get_next_port(const struct device_node *parent, | 588 | * Cleanup the in-kernel objects, freeing memory. To be called at the very end |
| 2007 | struct device_node *prev) | 589 | * of the remove sequence, when nothing (including userspace) can access the |
| 590 | * objects anymore. | ||
| 591 | */ | ||
| 592 | static void cal_media_cleanup(struct cal_dev *cal) | ||
| 2008 | { | 593 | { |
| 2009 | struct device_node *port = NULL; | 594 | unsigned int i; |
| 2010 | |||
| 2011 | if (!parent) | ||
| 2012 | return NULL; | ||
| 2013 | 595 | ||
| 2014 | if (!prev) { | 596 | for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { |
| 2015 | struct device_node *ports; | 597 | if (cal->ctx[i]) |
| 2016 | /* | 598 | cal_ctx_v4l2_cleanup(cal->ctx[i]); |
| 2017 | * It's the first call, we have to find a port subnode | ||
| 2018 | * within this node or within an optional 'ports' node. | ||
| 2019 | */ | ||
| 2020 | ports = of_get_child_by_name(parent, "ports"); | ||
| 2021 | if (ports) | ||
| 2022 | parent = ports; | ||
| 2023 | |||
| 2024 | port = of_get_child_by_name(parent, "port"); | ||
| 2025 | |||
| 2026 | /* release the 'ports' node */ | ||
| 2027 | of_node_put(ports); | ||
| 2028 | } else { | ||
| 2029 | struct device_node *ports; | ||
| 2030 | |||
| 2031 | ports = of_get_parent(prev); | ||
| 2032 | if (!ports) | ||
| 2033 | return NULL; | ||
| 2034 | |||
| 2035 | do { | ||
| 2036 | port = of_get_next_child(ports, prev); | ||
| 2037 | if (!port) { | ||
| 2038 | of_node_put(ports); | ||
| 2039 | return NULL; | ||
| 2040 | } | ||
| 2041 | prev = port; | ||
| 2042 | } while (!of_node_name_eq(port, "port")); | ||
| 2043 | of_node_put(ports); | ||
| 2044 | } | 599 | } |
| 2045 | 600 | ||
| 2046 | return port; | 601 | v4l2_device_unregister(&cal->v4l2_dev); |
| 2047 | } | 602 | media_device_cleanup(&cal->mdev); |
| 2048 | |||
| 2049 | static struct device_node * | ||
| 2050 | of_get_next_endpoint(const struct device_node *parent, | ||
| 2051 | struct device_node *prev) | ||
| 2052 | { | ||
| 2053 | struct device_node *ep = NULL; | ||
| 2054 | |||
| 2055 | if (!parent) | ||
| 2056 | return NULL; | ||
| 2057 | 603 | ||
| 2058 | do { | 604 | vb2_dma_contig_clear_max_seg_size(cal->dev); |
| 2059 | ep = of_get_next_child(parent, prev); | ||
| 2060 | if (!ep) | ||
| 2061 | return NULL; | ||
| 2062 | prev = ep; | ||
| 2063 | } while (!of_node_name_eq(ep, "endpoint")); | ||
| 2064 | |||
| 2065 | return ep; | ||
| 2066 | } | 605 | } |
| 2067 | 606 | ||
| 2068 | static int of_cal_create_instance(struct cal_ctx *ctx, int inst) | 607 | /* ------------------------------------------------------------------ |
| 2069 | { | 608 | * Initialization and module stuff |
| 2070 | struct platform_device *pdev = ctx->dev->pdev; | 609 | * ------------------------------------------------------------------ |
| 2071 | struct device_node *ep_node, *port, *sensor_node, *parent; | 610 | */ |
| 2072 | struct v4l2_fwnode_endpoint *endpoint; | ||
| 2073 | struct v4l2_async_subdev *asd; | ||
| 2074 | u32 regval = 0; | ||
| 2075 | int ret, index, found_port = 0, lane; | ||
| 2076 | |||
| 2077 | parent = pdev->dev.of_node; | ||
| 2078 | |||
| 2079 | endpoint = &ctx->endpoint; | ||
| 2080 | |||
| 2081 | ep_node = NULL; | ||
| 2082 | port = NULL; | ||
| 2083 | sensor_node = NULL; | ||
| 2084 | ret = -EINVAL; | ||
| 2085 | |||
| 2086 | ctx_dbg(3, ctx, "Scanning Port node for csi2 port: %d\n", inst); | ||
| 2087 | for (index = 0; index < CAL_NUM_CSI2_PORTS; index++) { | ||
| 2088 | port = of_get_next_port(parent, port); | ||
| 2089 | if (!port) { | ||
| 2090 | ctx_dbg(1, ctx, "No port node found for csi2 port:%d\n", | ||
| 2091 | index); | ||
| 2092 | goto cleanup_exit; | ||
| 2093 | } | ||
| 2094 | |||
| 2095 | /* Match the slice number with <REG> */ | ||
| 2096 | of_property_read_u32(port, "reg", ®val); | ||
| 2097 | ctx_dbg(3, ctx, "port:%d inst:%d <reg>:%d\n", | ||
| 2098 | index, inst, regval); | ||
| 2099 | if ((regval == inst) && (index == inst)) { | ||
| 2100 | found_port = 1; | ||
| 2101 | break; | ||
| 2102 | } | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | if (!found_port) { | ||
| 2106 | ctx_dbg(1, ctx, "No port node matches csi2 port:%d\n", | ||
| 2107 | inst); | ||
| 2108 | goto cleanup_exit; | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | ctx_dbg(3, ctx, "Scanning sub-device for csi2 port: %d\n", | ||
| 2112 | inst); | ||
| 2113 | |||
| 2114 | ep_node = of_get_next_endpoint(port, ep_node); | ||
| 2115 | if (!ep_node) { | ||
| 2116 | ctx_dbg(3, ctx, "can't get next endpoint\n"); | ||
| 2117 | goto cleanup_exit; | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | sensor_node = of_graph_get_remote_port_parent(ep_node); | ||
| 2121 | if (!sensor_node) { | ||
| 2122 | ctx_dbg(3, ctx, "can't get remote parent\n"); | ||
| 2123 | goto cleanup_exit; | ||
| 2124 | } | ||
| 2125 | |||
| 2126 | v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint); | ||
| 2127 | |||
| 2128 | if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY) { | ||
| 2129 | ctx_err(ctx, "Port:%d sub-device %pOFn is not a CSI2 device\n", | ||
| 2130 | inst, sensor_node); | ||
| 2131 | goto cleanup_exit; | ||
| 2132 | } | ||
| 2133 | |||
| 2134 | /* Store Virtual Channel number */ | ||
| 2135 | ctx->virtual_channel = endpoint->base.id; | ||
| 2136 | |||
| 2137 | ctx_dbg(3, ctx, "Port:%d v4l2-endpoint: CSI2\n", inst); | ||
| 2138 | ctx_dbg(3, ctx, "Virtual Channel=%d\n", ctx->virtual_channel); | ||
| 2139 | ctx_dbg(3, ctx, "flags=0x%08x\n", endpoint->bus.mipi_csi2.flags); | ||
| 2140 | ctx_dbg(3, ctx, "clock_lane=%d\n", endpoint->bus.mipi_csi2.clock_lane); | ||
| 2141 | ctx_dbg(3, ctx, "num_data_lanes=%d\n", | ||
| 2142 | endpoint->bus.mipi_csi2.num_data_lanes); | ||
| 2143 | ctx_dbg(3, ctx, "data_lanes= <\n"); | ||
| 2144 | for (lane = 0; lane < endpoint->bus.mipi_csi2.num_data_lanes; lane++) | ||
| 2145 | ctx_dbg(3, ctx, "\t%d\n", | ||
| 2146 | endpoint->bus.mipi_csi2.data_lanes[lane]); | ||
| 2147 | ctx_dbg(3, ctx, "\t>\n"); | ||
| 2148 | |||
| 2149 | ctx_dbg(1, ctx, "Port: %d found sub-device %pOFn\n", | ||
| 2150 | inst, sensor_node); | ||
| 2151 | |||
| 2152 | v4l2_async_notifier_init(&ctx->notifier); | ||
| 2153 | |||
| 2154 | asd = kzalloc(sizeof(*asd), GFP_KERNEL); | ||
| 2155 | if (!asd) | ||
| 2156 | goto cleanup_exit; | ||
| 2157 | |||
| 2158 | asd->match_type = V4L2_ASYNC_MATCH_FWNODE; | ||
| 2159 | asd->match.fwnode = of_fwnode_handle(sensor_node); | ||
| 2160 | |||
| 2161 | ret = v4l2_async_notifier_add_subdev(&ctx->notifier, asd); | ||
| 2162 | if (ret) { | ||
| 2163 | ctx_err(ctx, "Error adding asd\n"); | ||
| 2164 | kfree(asd); | ||
| 2165 | goto cleanup_exit; | ||
| 2166 | } | ||
| 2167 | |||
| 2168 | ctx->notifier.ops = &cal_async_ops; | ||
| 2169 | ret = v4l2_async_notifier_register(&ctx->v4l2_dev, | ||
| 2170 | &ctx->notifier); | ||
| 2171 | if (ret) { | ||
| 2172 | ctx_err(ctx, "Error registering async notifier\n"); | ||
| 2173 | v4l2_async_notifier_cleanup(&ctx->notifier); | ||
| 2174 | ret = -EINVAL; | ||
| 2175 | } | ||
| 2176 | |||
| 2177 | /* | ||
| 2178 | * On success we need to keep reference on sensor_node, or | ||
| 2179 | * if notifier_cleanup was called above, sensor_node was | ||
| 2180 | * already put. | ||
| 2181 | */ | ||
| 2182 | sensor_node = NULL; | ||
| 2183 | |||
| 2184 | cleanup_exit: | ||
| 2185 | of_node_put(sensor_node); | ||
| 2186 | of_node_put(ep_node); | ||
| 2187 | of_node_put(port); | ||
| 2188 | |||
| 2189 | return ret; | ||
| 2190 | } | ||
| 2191 | 611 | ||
| 2192 | static struct cal_ctx *cal_create_instance(struct cal_dev *dev, int inst) | 612 | static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) |
| 2193 | { | 613 | { |
| 2194 | struct cal_ctx *ctx; | 614 | struct cal_ctx *ctx; |
| 2195 | struct v4l2_ctrl_handler *hdl; | ||
| 2196 | int ret; | 615 | int ret; |
| 2197 | 616 | ||
| 2198 | ctx = devm_kzalloc(&dev->pdev->dev, sizeof(*ctx), GFP_KERNEL); | 617 | ctx = devm_kzalloc(cal->dev, sizeof(*ctx), GFP_KERNEL); |
| 2199 | if (!ctx) | 618 | if (!ctx) |
| 2200 | return NULL; | 619 | return NULL; |
| 2201 | 620 | ||
| 2202 | /* save the cal_dev * for future ref */ | 621 | ctx->cal = cal; |
| 2203 | ctx->dev = dev; | 622 | ctx->phy = cal->phy[inst]; |
| 623 | ctx->index = inst; | ||
| 624 | ctx->cport = inst; | ||
| 2204 | 625 | ||
| 2205 | snprintf(ctx->v4l2_dev.name, sizeof(ctx->v4l2_dev.name), | 626 | ret = cal_ctx_v4l2_init(ctx); |
| 2206 | "%s-%03d", CAL_MODULE_NAME, inst); | ||
| 2207 | ret = v4l2_device_register(&dev->pdev->dev, &ctx->v4l2_dev); | ||
| 2208 | if (ret) | 627 | if (ret) |
| 2209 | goto err_exit; | 628 | return NULL; |
| 2210 | |||
| 2211 | hdl = &ctx->ctrl_handler; | ||
| 2212 | ret = v4l2_ctrl_handler_init(hdl, 11); | ||
| 2213 | if (ret) { | ||
| 2214 | ctx_err(ctx, "Failed to init ctrl handler\n"); | ||
| 2215 | goto unreg_dev; | ||
| 2216 | } | ||
| 2217 | ctx->v4l2_dev.ctrl_handler = hdl; | ||
| 2218 | |||
| 2219 | /* Make sure Camera Core H/W register area is available */ | ||
| 2220 | ctx->cc = dev->cc[inst]; | ||
| 2221 | |||
| 2222 | /* Store the instance id */ | ||
| 2223 | ctx->csi2_port = inst + 1; | ||
| 2224 | 629 | ||
| 2225 | ret = of_cal_create_instance(ctx, inst); | ||
| 2226 | if (ret) { | ||
| 2227 | ret = -EINVAL; | ||
| 2228 | goto free_hdl; | ||
| 2229 | } | ||
| 2230 | return ctx; | 630 | return ctx; |
| 2231 | |||
| 2232 | free_hdl: | ||
| 2233 | v4l2_ctrl_handler_free(hdl); | ||
| 2234 | unreg_dev: | ||
| 2235 | v4l2_device_unregister(&ctx->v4l2_dev); | ||
| 2236 | err_exit: | ||
| 2237 | return NULL; | ||
| 2238 | } | 631 | } |
| 2239 | 632 | ||
| 2240 | static const struct of_device_id cal_of_match[] = { | 633 | static const struct of_device_id cal_of_match[] = { |
| @@ -2258,191 +651,253 @@ static const struct of_device_id cal_of_match[] = { · 17 unmodified lines | |||
| 2258 | }; | 651 | }; |
| 2259 | MODULE_DEVICE_TABLE(of, cal_of_match); | 652 | MODULE_DEVICE_TABLE(of, cal_of_match); |
| 2260 | 653 | ||
| 654 | /* Get hardware revision and info. */ | ||
| 655 | |||
| 656 | #define CAL_HL_HWINFO_VALUE 0xa3c90469 | ||
| 657 | |||
| 658 | static void cal_get_hwinfo(struct cal_dev *cal) | ||
| 659 | { | ||
| 660 | u32 hwinfo; | ||
| 661 | |||
| 662 | cal->revision = cal_read(cal, CAL_HL_REVISION); | ||
| 663 | switch (FIELD_GET(CAL_HL_REVISION_SCHEME_MASK, cal->revision)) { | ||
| 664 | case CAL_HL_REVISION_SCHEME_H08: | ||
| 665 | cal_dbg(3, cal, "CAL HW revision %lu.%lu.%lu (0x%08x)\n", | ||
| 666 | FIELD_GET(CAL_HL_REVISION_MAJOR_MASK, cal->revision), | ||
| 667 | FIELD_GET(CAL_HL_REVISION_MINOR_MASK, cal->revision), | ||
| 668 | FIELD_GET(CAL_HL_REVISION_RTL_MASK, cal->revision), | ||
| 669 | cal->revision); | ||
| 670 | break; | ||
| 671 | |||
| 672 | case CAL_HL_REVISION_SCHEME_LEGACY: | ||
| 673 | default: | ||
| 674 | cal_info(cal, "Unexpected CAL HW revision 0x%08x\n", | ||
| 675 | cal->revision); | ||
| 676 | break; | ||
| 677 | } | ||
| 678 | |||
| 679 | hwinfo = cal_read(cal, CAL_HL_HWINFO); | ||
| 680 | if (hwinfo != CAL_HL_HWINFO_VALUE) | ||
| 681 | cal_info(cal, "CAL_HL_HWINFO = 0x%08x, expected 0x%08x\n", | ||
| 682 | hwinfo, CAL_HL_HWINFO_VALUE); | ||
| 683 | } | ||
| 684 | |||
| 685 | static int cal_init_camerarx_regmap(struct cal_dev *cal) | ||
| 686 | { | ||
| 687 | struct platform_device *pdev = to_platform_device(cal->dev); | ||
| 688 | struct device_node *np = cal->dev->of_node; | ||
| 689 | struct regmap_config config = { }; | ||
| 690 | struct regmap *syscon; | ||
| 691 | struct resource *res; | ||
| 692 | unsigned int offset; | ||
| 693 | void __iomem *base; | ||
| 694 | |||
| 695 | syscon = syscon_regmap_lookup_by_phandle_args(np, "ti,camerrx-control", | ||
| 696 | 1, &offset); | ||
| 697 | if (!IS_ERR(syscon)) { | ||
| 698 | cal->syscon_camerrx = syscon; | ||
| 699 | cal->syscon_camerrx_offset = offset; | ||
| 700 | return 0; | ||
| 701 | } | ||
| 702 | |||
| 703 | dev_warn(cal->dev, "failed to get ti,camerrx-control: %ld\n", | ||
| 704 | PTR_ERR(syscon)); | ||
| 705 | |||
| 706 | /* | ||
| 707 | * Backward DTS compatibility. If syscon entry is not present then | ||
| 708 | * check if the camerrx_control resource is present. | ||
| 709 | */ | ||
| 710 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
| 711 | "camerrx_control"); | ||
| 712 | base = devm_ioremap_resource(cal->dev, res); | ||
| 713 | if (IS_ERR(base)) { | ||
| 714 | cal_err(cal, "failed to ioremap camerrx_control\n"); | ||
| 715 | return PTR_ERR(base); | ||
| 716 | } | ||
| 717 | |||
| 718 | cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", | ||
| 719 | res->name, &res->start, &res->end); | ||
| 720 | |||
| 721 | config.reg_bits = 32; | ||
| 722 | config.reg_stride = 4; | ||
| 723 | config.val_bits = 32; | ||
| 724 | config.max_register = resource_size(res) - 4; | ||
| 725 | |||
| 726 | syscon = regmap_init_mmio(NULL, base, &config); | ||
| 727 | if (IS_ERR(syscon)) { | ||
| 728 | pr_err("regmap init failed\n"); | ||
| 729 | return PTR_ERR(syscon); | ||
| 730 | } | ||
| 731 | |||
| 732 | /* | ||
| 733 | * In this case the base already point to the direct CM register so no | ||
| 734 | * need for an offset. | ||
| 735 | */ | ||
| 736 | cal->syscon_camerrx = syscon; | ||
| 737 | cal->syscon_camerrx_offset = 0; | ||
| 738 | |||
| 739 | return 0; | ||
| 740 | } | ||
| 741 | |||
| 2261 | static int cal_probe(struct platform_device *pdev) | 742 | static int cal_probe(struct platform_device *pdev) |
| 2262 | { | 743 | { |
| 2263 | struct cal_dev *dev; | 744 | struct cal_dev *cal; |
| 2264 | struct cal_ctx *ctx; | 745 | struct cal_ctx *ctx; |
| 2265 | struct device_node *parent = pdev->dev.of_node; | 746 | bool connected = false; |
| 2266 | struct regmap *syscon_camerrx = NULL; | 747 | unsigned int i; |
| 2267 | u32 syscon_camerrx_offset = 0; | ||
| 2268 | int ret; | 748 | int ret; |
| 2269 | int irq; | 749 | int irq; |
| 2270 | int i; | ||
| 2271 | 750 | ||
| 2272 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | 751 | cal = devm_kzalloc(&pdev->dev, sizeof(*cal), GFP_KERNEL); |
| 2273 | if (!dev) | 752 | if (!cal) |
| 2274 | return -ENOMEM; | 753 | return -ENOMEM; |
| 2275 | 754 | ||
| 2276 | dev->data = of_device_get_match_data(&pdev->dev); | 755 | cal->data = of_device_get_match_data(&pdev->dev); |
| 2277 | if (!dev->data) { | 756 | if (!cal->data) { |
| 2278 | dev_err(&pdev->dev, "Could not get feature data based on compatible version\n"); | 757 | dev_err(&pdev->dev, "Could not get feature data based on compatible version\n"); |
| 2279 | return -ENODEV; | 758 | return -ENODEV; |
| 2280 | } | 759 | } |
| 2281 | 760 | ||
| 2282 | dev->flags = dev->data->flags; | 761 | cal->dev = &pdev->dev; |
| 762 | platform_set_drvdata(pdev, cal); | ||
| 2283 | 763 | ||
| 2284 | /* set pseudo v4l2 device name so we can use v4l2_printk */ | 764 | /* Acquire resources: clocks, CAMERARX regmap, I/O memory and IRQ. */ |
| 2285 | strscpy(dev->v4l2_dev.name, CAL_MODULE_NAME, | 765 | cal->fclk = devm_clk_get(&pdev->dev, "fck"); |
| 2286 | sizeof(dev->v4l2_dev.name)); | 766 | if (IS_ERR(cal->fclk)) { |
| 2287 | |||
| 2288 | /* save pdev pointer */ | ||
| 2289 | dev->pdev = pdev; | ||
| 2290 | |||
| 2291 | dev->fclk = devm_clk_get(&pdev->dev, "fck"); | ||
| 2292 | if (IS_ERR(dev->fclk)) { | ||
| 2293 | dev_err(&pdev->dev, "cannot get CAL fclk\n"); | 767 | dev_err(&pdev->dev, "cannot get CAL fclk\n"); |
| 2294 | return PTR_ERR(dev->fclk); | 768 | return PTR_ERR(cal->fclk); |
| 2295 | } | ||
| 2296 | |||
| 2297 | syscon_camerrx = syscon_regmap_lookup_by_phandle(parent, | ||
| 2298 | "ti,camerrx-control"); | ||
| 2299 | ret = of_property_read_u32_index(parent, "ti,camerrx-control", 1, | ||
| 2300 | &syscon_camerrx_offset); | ||
| 2301 | if (IS_ERR(syscon_camerrx)) | ||
| 2302 | ret = PTR_ERR(syscon_camerrx); | ||
| 2303 | if (ret) { | ||
| 2304 | dev_warn(&pdev->dev, "failed to get ti,camerrx-control: %d\n", | ||
| 2305 | ret); | ||
| 2306 | |||
| 2307 | /* | ||
| 2308 | * Backward DTS compatibility. | ||
| 2309 | * If syscon entry is not present then check if the | ||
| 2310 | * camerrx_control resource is present. | ||
| 2311 | */ | ||
| 2312 | syscon_camerrx = cal_get_camerarx_regmap(dev); | ||
| 2313 | if (IS_ERR(syscon_camerrx)) { | ||
| 2314 | dev_err(&pdev->dev, "failed to get camerrx_control regmap\n"); | ||
| 2315 | return PTR_ERR(syscon_camerrx); | ||
| 2316 | } | ||
| 2317 | /* In this case the base already point to the direct | ||
| 2318 | * CM register so no need for an offset | ||
| 2319 | */ | ||
| 2320 | syscon_camerrx_offset = 0; | ||
| 2321 | } | 769 | } |
| 2322 | 770 | ||
| 2323 | dev->syscon_camerrx = syscon_camerrx; | 771 | ret = cal_init_camerarx_regmap(cal); |
| 2324 | dev->syscon_camerrx_offset = syscon_camerrx_offset; | 772 | if (ret < 0) |
| 2325 | ret = cal_camerarx_regmap_init(dev); | ||
| 2326 | if (ret) | ||
| 2327 | return ret; | 773 | return ret; |
| 2328 | 774 | ||
| 2329 | dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 775 | cal->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| 2330 | "cal_top"); | 776 | "cal_top"); |
| 2331 | dev->base = devm_ioremap_resource(&pdev->dev, dev->res); | 777 | cal->base = devm_ioremap_resource(&pdev->dev, cal->res); |
| 2332 | if (IS_ERR(dev->base)) | 778 | if (IS_ERR(cal->base)) |
| 2333 | return PTR_ERR(dev->base); | 779 | return PTR_ERR(cal->base); |
| 2334 | 780 | ||
| 2335 | cal_dbg(1, dev, "ioresource %s at %pa - %pa\n", | 781 | cal_dbg(1, cal, "ioresource %s at %pa - %pa\n", |
| 2336 | dev->res->name, &dev->res->start, &dev->res->end); | 782 | cal->res->name, &cal->res->start, &cal->res->end); |
| 2337 | 783 | ||
| 2338 | irq = platform_get_irq(pdev, 0); | 784 | irq = platform_get_irq(pdev, 0); |
| 2339 | cal_dbg(1, dev, "got irq# %d\n", irq); | 785 | cal_dbg(1, cal, "got irq# %d\n", irq); |
| 2340 | ret = devm_request_irq(&pdev->dev, irq, cal_irq, 0, CAL_MODULE_NAME, | 786 | ret = devm_request_irq(&pdev->dev, irq, cal_irq, 0, CAL_MODULE_NAME, |
| 2341 | dev); | 787 | cal); |
| 2342 | if (ret) | 788 | if (ret) |
| 2343 | return ret; | 789 | return ret; |
| 2344 | 790 | ||
| 2345 | platform_set_drvdata(pdev, dev); | 791 | /* Read the revision and hardware info to verify hardware access. */ |
| 792 | pm_runtime_enable(&pdev->dev); | ||
| 793 | ret = pm_runtime_get_sync(&pdev->dev); | ||
| 794 | if (ret) | ||
| 795 | goto error_pm_runtime; | ||
| 2346 | 796 | ||
| 2347 | dev->cc[0] = cc_create(dev, 0); | 797 | cal_get_hwinfo(cal); |
| 2348 | if (IS_ERR(dev->cc[0])) | 798 | pm_runtime_put_sync(&pdev->dev); |
| 2349 | return PTR_ERR(dev->cc[0]); | ||
| 2350 | 799 | ||
| 2351 | if (cal_data_get_num_csi2_phy(dev) > 1) { | 800 | /* Create CAMERARX PHYs. */ |
| 2352 | dev->cc[1] = cc_create(dev, 1); | 801 | for (i = 0; i < cal->data->num_csi2_phy; ++i) { |
| 2353 | if (IS_ERR(dev->cc[1])) | 802 | cal->phy[i] = cal_camerarx_create(cal, i); |
| 2354 | return PTR_ERR(dev->cc[1]); | 803 | if (IS_ERR(cal->phy[i])) { |
| 2355 | } else { | 804 | ret = PTR_ERR(cal->phy[i]); |
| 2356 | dev->cc[1] = NULL; | 805 | cal->phy[i] = NULL; |
| 2357 | } | 806 | goto error_camerarx; |
| 807 | } | ||
| 2358 | 808 | ||
| 2359 | dev->ctx[0] = NULL; | 809 | if (cal->phy[i]->sensor_node) |
| 2360 | dev->ctx[1] = NULL; | 810 | connected = true; |
| 811 | } | ||
| 2361 | 812 | ||
| 2362 | dev->ctx[0] = cal_create_instance(dev, 0); | 813 | if (!connected) { |
| 2363 | if (cal_data_get_num_csi2_phy(dev) > 1) | 814 | cal_err(cal, "Neither port is configured, no point in staying up\n"); |
| 2364 | dev->ctx[1] = cal_create_instance(dev, 1); | 815 | ret = -ENODEV; |
| 2365 | if (!dev->ctx[0] && !dev->ctx[1]) { | 816 | goto error_camerarx; |
| 2366 | cal_err(dev, "Neither port is configured, no point in staying up\n"); | ||
| 2367 | return -ENODEV; | ||
| 2368 | } | 817 | } |
| 2369 | 818 | ||
| 2370 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); | 819 | /* Initialize the media device. */ |
| 820 | ret = cal_media_init(cal); | ||
| 821 | if (ret < 0) | ||
| 822 | goto error_camerarx; | ||
| 2371 | 823 | ||
| 2372 | pm_runtime_enable(&pdev->dev); | 824 | /* Create contexts. */ |
| 825 | for (i = 0; i < cal->data->num_csi2_phy; ++i) { | ||
| 826 | if (!cal->phy[i]->sensor_node) | ||
| 827 | continue; | ||
| 2373 | 828 | ||
| 2374 | ret = pm_runtime_get_sync(&pdev->dev); | 829 | cal->ctx[i] = cal_ctx_create(cal, i); |
| 830 | if (!cal->ctx[i]) { | ||
| 831 | cal_err(cal, "Failed to create context %u\n", i); | ||
| 832 | ret = -ENODEV; | ||
| 833 | goto error_context; | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | /* Register the media device. */ | ||
| 838 | ret = cal_media_register(cal); | ||
| 2375 | if (ret) | 839 | if (ret) |
| 2376 | goto runtime_disable; | 840 | goto error_context; |
| 2377 | 841 | ||
| 2378 | /* Just check we can actually access the module */ | 842 | return 0; |
| 2379 | cal_get_hwinfo(dev); | ||
| 2380 | 843 | ||
| 2381 | pm_runtime_put_sync(&pdev->dev); | 844 | error_context: |
| 845 | for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { | ||
| 846 | ctx = cal->ctx[i]; | ||
| 847 | if (ctx) | ||
| 848 | cal_ctx_v4l2_cleanup(ctx); | ||
| 849 | } | ||
| 2382 | 850 | ||
| 2383 | return 0; | 851 | cal_media_cleanup(cal); |
| 2384 | 852 | ||
| 2385 | runtime_disable: | 853 | error_camerarx: |
| 2386 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); | 854 | for (i = 0; i < ARRAY_SIZE(cal->phy); i++) |
| 855 | cal_camerarx_destroy(cal->phy[i]); | ||
| 2387 | 856 | ||
| 857 | error_pm_runtime: | ||
| 2388 | pm_runtime_disable(&pdev->dev); | 858 | pm_runtime_disable(&pdev->dev); |
| 2389 | for (i = 0; i < CAL_NUM_CONTEXT; i++) { | ||
| 2390 | ctx = dev->ctx[i]; | ||
| 2391 | if (ctx) { | ||
| 2392 | v4l2_async_notifier_unregister(&ctx->notifier); | ||
| 2393 | v4l2_async_notifier_cleanup(&ctx->notifier); | ||
| 2394 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
| 2395 | v4l2_device_unregister(&ctx->v4l2_dev); | ||
| 2396 | } | ||
| 2397 | } | ||
| 2398 | 859 | ||
| 2399 | return ret; | 860 | return ret; |
| 2400 | } | 861 | } |
| 2401 | 862 | ||
| 2402 | static int cal_remove(struct platform_device *pdev) | 863 | static int cal_remove(struct platform_device *pdev) |
| 2403 | { | 864 | { |
| 2404 | struct cal_dev *dev = | 865 | struct cal_dev *cal = platform_get_drvdata(pdev); |
| 2405 | (struct cal_dev *)platform_get_drvdata(pdev); | 866 | unsigned int i; |
| 2406 | struct cal_ctx *ctx; | ||
| 2407 | int i; | ||
| 2408 | 867 | ||
| 2409 | cal_dbg(1, dev, "Removing %s\n", CAL_MODULE_NAME); | 868 | cal_dbg(1, cal, "Removing %s\n", CAL_MODULE_NAME); |
| 2410 | 869 | ||
| 2411 | pm_runtime_get_sync(&pdev->dev); | 870 | pm_runtime_get_sync(&pdev->dev); |
| 2412 | 871 | ||
| 2413 | for (i = 0; i < CAL_NUM_CONTEXT; i++) { | 872 | cal_media_unregister(cal); |
| 2414 | ctx = dev->ctx[i]; | 873 | |
| 2415 | if (ctx) { | 874 | for (i = 0; i < ARRAY_SIZE(cal->phy); i++) { |
| 2416 | ctx_dbg(1, ctx, "unregistering %s\n", | 875 | if (cal->phy[i]) |
| 2417 | video_device_node_name(&ctx->vdev)); | 876 | cal_camerarx_disable(cal->phy[i]); |
| 2418 | camerarx_phy_disable(ctx); | ||
| 2419 | v4l2_async_notifier_unregister(&ctx->notifier); | ||
| 2420 | v4l2_async_notifier_cleanup(&ctx->notifier); | ||
| 2421 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
| 2422 | v4l2_device_unregister(&ctx->v4l2_dev); | ||
| 2423 | video_unregister_device(&ctx->vdev); | ||
| 2424 | } | ||
| 2425 | } | 877 | } |
| 2426 | 878 | ||
| 879 | cal_media_cleanup(cal); | ||
| 880 | |||
| 881 | for (i = 0; i < ARRAY_SIZE(cal->phy); i++) | ||
| 882 | cal_camerarx_destroy(cal->phy[i]); | ||
| 883 | |||
| 2427 | pm_runtime_put_sync(&pdev->dev); | 884 | pm_runtime_put_sync(&pdev->dev); |
| 2428 | pm_runtime_disable(&pdev->dev); | 885 | pm_runtime_disable(&pdev->dev); |
| 2429 | 886 | ||
| 2430 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); | ||
| 2431 | |||
| 2432 | return 0; | 887 | return 0; |
| 2433 | } | 888 | } |
| 2434 | 889 | ||
| 2435 | static int cal_runtime_resume(struct device *dev) | 890 | static int cal_runtime_resume(struct device *dev) |
| 2436 | { | 891 | { |
| 2437 | struct cal_dev *caldev = dev_get_drvdata(dev); | 892 | struct cal_dev *cal = dev_get_drvdata(dev); |
| 2438 | 893 | ||
| 2439 | if (caldev->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) { | 894 | if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) { |
| 2440 | /* | 895 | /* |
| 2441 | * Apply errata on both port everytime we (re-)enable | 896 | * Apply errata on both port everytime we (re-)enable |
| 2442 | * the clock | 897 | * the clock |
| 2443 | */ | 898 | */ |
| 2444 | i913_errata(caldev, 0); | 899 | cal_camerarx_i913_errata(cal->phy[0]); |
| 2445 | i913_errata(caldev, 1); | 900 | cal_camerarx_i913_errata(cal->phy[1]); |
| 2446 | } | 901 | } |
| 2447 | 902 | ||
| 2448 | return 0; | 903 | return 0; |
| @@ -0,0 +1,267 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-only */ | ||
| 2 | /* | ||
| 3 | * TI Camera Access Layer (CAL) | ||
| 4 | * | ||
| 5 | * Copyright (c) 2015-2020 Texas Instruments Inc. | ||
| 6 | * | ||
| 7 | * Authors: | ||
| 8 | * Benoit Parrot <bparrot@ti.com> | ||
| 9 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
| 10 | */ | ||
| 11 | #ifndef __TI_CAL_H__ | ||
| 12 | #define __TI_CAL_H__ | ||
| 13 | |||
| 14 | #include <linux/bitfield.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/list.h> | ||
| 17 | #include <linux/mutex.h> | ||
| 18 | #include <linux/spinlock.h> | ||
| 19 | #include <linux/videodev2.h> | ||
| 20 | |||
| 21 | #include <media/media-device.h> | ||
| 22 | #include <media/v4l2-async.h> | ||
| 23 | #include <media/v4l2-ctrls.h> | ||
| 24 | #include <media/v4l2-dev.h> | ||
| 25 | #include <media/v4l2-device.h> | ||
| 26 | #include <media/v4l2-fwnode.h> | ||
| 27 | #include <media/videobuf2-v4l2.h> | ||
| 28 | |||
| 29 | #define CAL_MODULE_NAME "cal" | ||
| 30 | #define CAL_NUM_CONTEXT 2 | ||
| 31 | #define CAL_NUM_CSI2_PORTS 2 | ||
| 32 | |||
| 33 | #define MAX_WIDTH_BYTES (8192 * 8) | ||
| 34 | #define MAX_HEIGHT_LINES 16383 | ||
| 35 | |||
| 36 | struct device; | ||
| 37 | struct device_node; | ||
| 38 | struct resource; | ||
| 39 | struct regmap; | ||
| 40 | struct regmap_fied; | ||
| 41 | struct v4l2_subdev; | ||
| 42 | |||
| 43 | /* CTRL_CORE_CAMERRX_CONTROL register field id */ | ||
| 44 | enum cal_camerarx_field { | ||
| 45 | F_CTRLCLKEN, | ||
| 46 | F_CAMMODE, | ||
| 47 | F_LANEENABLE, | ||
| 48 | F_CSI_MODE, | ||
| 49 | F_MAX_FIELDS, | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct cal_fmt { | ||
| 53 | u32 fourcc; | ||
| 54 | u32 code; | ||
| 55 | /* Bits per pixel */ | ||
| 56 | u8 bpp; | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* buffer for one video frame */ | ||
| 60 | struct cal_buffer { | ||
| 61 | /* common v4l buffer stuff -- must be first */ | ||
| 62 | struct vb2_v4l2_buffer vb; | ||
| 63 | struct list_head list; | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct cal_dmaqueue { | ||
| 67 | struct list_head active; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct cal_camerarx_data { | ||
| 71 | struct { | ||
| 72 | unsigned int lsb; | ||
| 73 | unsigned int msb; | ||
| 74 | } fields[F_MAX_FIELDS]; | ||
| 75 | unsigned int num_lanes; | ||
| 76 | }; | ||
| 77 | |||
| 78 | struct cal_data { | ||
| 79 | const struct cal_camerarx_data *camerarx; | ||
| 80 | unsigned int num_csi2_phy; | ||
| 81 | unsigned int flags; | ||
| 82 | }; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * The Camera Adaptation Layer (CAL) module is paired with one or more complex | ||
| 86 | * I/O PHYs (CAMERARX). It contains multiple instances of CSI-2, processing and | ||
| 87 | * DMA contexts. | ||
| 88 | * | ||
| 89 | * The cal_dev structure represents the whole subsystem, including the CAL and | ||
| 90 | * the CAMERARX instances. Instances of struct cal_dev are named cal through the | ||
| 91 | * driver. | ||
| 92 | * | ||
| 93 | * The cal_camerarx structure represents one CAMERARX instance. Instances of | ||
| 94 | * cal_camerarx are named phy through the driver. | ||
| 95 | * | ||
| 96 | * The cal_ctx structure represents the combination of one CSI-2 context, one | ||
| 97 | * processing context and one DMA context. Instance of struct cal_ctx are named | ||
| 98 | * ctx through the driver. | ||
| 99 | */ | ||
| 100 | |||
| 101 | struct cal_camerarx { | ||
| 102 | void __iomem *base; | ||
| 103 | struct resource *res; | ||
| 104 | struct device *dev; | ||
| 105 | struct regmap_field *fields[F_MAX_FIELDS]; | ||
| 106 | |||
| 107 | struct cal_dev *cal; | ||
| 108 | unsigned int instance; | ||
| 109 | |||
| 110 | struct v4l2_fwnode_endpoint endpoint; | ||
| 111 | struct device_node *sensor_node; | ||
| 112 | struct v4l2_subdev *sensor; | ||
| 113 | }; | ||
| 114 | |||
| 115 | struct cal_dev { | ||
| 116 | struct clk *fclk; | ||
| 117 | int irq; | ||
| 118 | void __iomem *base; | ||
| 119 | struct resource *res; | ||
| 120 | struct device *dev; | ||
| 121 | |||
| 122 | const struct cal_data *data; | ||
| 123 | u32 revision; | ||
| 124 | |||
| 125 | /* Control Module handle */ | ||
| 126 | struct regmap *syscon_camerrx; | ||
| 127 | u32 syscon_camerrx_offset; | ||
| 128 | |||
| 129 | /* Camera Core Module handle */ | ||
| 130 | struct cal_camerarx *phy[CAL_NUM_CSI2_PORTS]; | ||
| 131 | |||
| 132 | struct cal_ctx *ctx[CAL_NUM_CONTEXT]; | ||
| 133 | |||
| 134 | struct media_device mdev; | ||
| 135 | struct v4l2_device v4l2_dev; | ||
| 136 | struct v4l2_async_notifier notifier; | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* | ||
| 140 | * There is one cal_ctx structure for each camera core context. | ||
| 141 | */ | ||
| 142 | struct cal_ctx { | ||
| 143 | struct v4l2_ctrl_handler ctrl_handler; | ||
| 144 | struct video_device vdev; | ||
| 145 | struct media_pad pad; | ||
| 146 | |||
| 147 | struct cal_dev *cal; | ||
| 148 | struct cal_camerarx *phy; | ||
| 149 | |||
| 150 | /* v4l2_ioctl mutex */ | ||
| 151 | struct mutex mutex; | ||
| 152 | /* v4l2 buffers lock */ | ||
| 153 | spinlock_t slock; | ||
| 154 | |||
| 155 | struct cal_dmaqueue vidq; | ||
| 156 | |||
| 157 | /* video capture */ | ||
| 158 | const struct cal_fmt *fmt; | ||
| 159 | /* Used to store current pixel format */ | ||
| 160 | struct v4l2_format v_fmt; | ||
| 161 | /* Used to store current mbus frame format */ | ||
| 162 | struct v4l2_mbus_framefmt m_fmt; | ||
| 163 | |||
| 164 | /* Current subdev enumerated format */ | ||
| 165 | const struct cal_fmt **active_fmt; | ||
| 166 | unsigned int num_active_fmt; | ||
| 167 | |||
| 168 | unsigned int sequence; | ||
| 169 | struct vb2_queue vb_vidq; | ||
| 170 | unsigned int index; | ||
| 171 | unsigned int cport; | ||
| 172 | |||
| 173 | /* Pointer pointing to current v4l2_buffer */ | ||
| 174 | struct cal_buffer *cur_frm; | ||
| 175 | /* Pointer pointing to next v4l2_buffer */ | ||
| 176 | struct cal_buffer *next_frm; | ||
| 177 | |||
| 178 | bool dma_act; | ||
| 179 | }; | ||
| 180 | |||
| 181 | extern unsigned int cal_debug; | ||
| 182 | extern int cal_video_nr; | ||
| 183 | |||
| 184 | #define cal_dbg(level, cal, fmt, arg...) \ | ||
| 185 | do { \ | ||
| 186 | if (cal_debug >= (level)) \ | ||
| 187 | dev_printk(KERN_DEBUG, (cal)->dev, fmt, ##arg); \ | ||
| 188 | } while (0) | ||
| 189 | #define cal_info(cal, fmt, arg...) \ | ||
| 190 | dev_info((cal)->dev, fmt, ##arg) | ||
| 191 | #define cal_err(cal, fmt, arg...) \ | ||
| 192 | dev_err((cal)->dev, fmt, ##arg) | ||
| 193 | |||
| 194 | #define ctx_dbg(level, ctx, fmt, arg...) \ | ||
| 195 | cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) | ||
| 196 | #define ctx_info(ctx, fmt, arg...) \ | ||
| 197 | cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) | ||
| 198 | #define ctx_err(ctx, fmt, arg...) \ | ||
| 199 | cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) | ||
| 200 | |||
| 201 | #define phy_dbg(level, phy, fmt, arg...) \ | ||
| 202 | cal_dbg(level, (phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) | ||
| 203 | #define phy_info(phy, fmt, arg...) \ | ||
| 204 | cal_info((phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) | ||
| 205 | #define phy_err(phy, fmt, arg...) \ | ||
| 206 | cal_err((phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) | ||
| 207 | |||
| 208 | static inline u32 cal_read(struct cal_dev *cal, u32 offset) | ||
| 209 | { | ||
| 210 | return ioread32(cal->base + offset); | ||
| 211 | } | ||
| 212 | |||
| 213 | static inline void cal_write(struct cal_dev *cal, u32 offset, u32 val) | ||
| 214 | { | ||
| 215 | iowrite32(val, cal->base + offset); | ||
| 216 | } | ||
| 217 | |||
| 218 | static inline u32 cal_read_field(struct cal_dev *cal, u32 offset, u32 mask) | ||
| 219 | { | ||
| 220 | return FIELD_GET(mask, cal_read(cal, offset)); | ||
| 221 | } | ||
| 222 | |||
| 223 | static inline void cal_write_field(struct cal_dev *cal, u32 offset, u32 value, | ||
| 224 | u32 mask) | ||
| 225 | { | ||
| 226 | u32 val = cal_read(cal, offset); | ||
| 227 | |||
| 228 | val &= ~mask; | ||
| 229 | val |= FIELD_PREP(mask, value); | ||
| 230 | cal_write(cal, offset, val); | ||
| 231 | } | ||
| 232 | |||
| 233 | static inline void cal_set_field(u32 *valp, u32 field, u32 mask) | ||
| 234 | { | ||
| 235 | u32 val = *valp; | ||
| 236 | |||
| 237 | val &= ~mask; | ||
| 238 | val |= (field << __ffs(mask)) & mask; | ||
| 239 | *valp = val; | ||
| 240 | } | ||
| 241 | |||
| 242 | void cal_quickdump_regs(struct cal_dev *cal); | ||
| 243 | |||
| 244 | void cal_camerarx_disable(struct cal_camerarx *phy); | ||
| 245 | int cal_camerarx_start(struct cal_camerarx *phy, const struct cal_fmt *fmt); | ||
| 246 | void cal_camerarx_stop(struct cal_camerarx *phy); | ||
| 247 | void cal_camerarx_enable_irqs(struct cal_camerarx *phy); | ||
| 248 | void cal_camerarx_disable_irqs(struct cal_camerarx *phy); | ||
| 249 | void cal_camerarx_ppi_enable(struct cal_camerarx *phy); | ||
| 250 | void cal_camerarx_ppi_disable(struct cal_camerarx *phy); | ||
| 251 | void cal_camerarx_i913_errata(struct cal_camerarx *phy); | ||
| 252 | struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, | ||
| 253 | unsigned int instance); | ||
| 254 | void cal_camerarx_destroy(struct cal_camerarx *phy); | ||
| 255 | |||
| 256 | void cal_ctx_csi2_config(struct cal_ctx *ctx); | ||
| 257 | void cal_ctx_pix_proc_config(struct cal_ctx *ctx); | ||
| 258 | void cal_ctx_wr_dma_config(struct cal_ctx *ctx, unsigned int width, | ||
| 259 | unsigned int height); | ||
| 260 | void cal_ctx_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr); | ||
| 261 | |||
| 262 | int cal_ctx_v4l2_register(struct cal_ctx *ctx); | ||
| 263 | void cal_ctx_v4l2_unregister(struct cal_ctx *ctx); | ||
| 264 | int cal_ctx_v4l2_init(struct cal_ctx *ctx); | ||
| 265 | void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx); | ||
| 266 | |||
| 267 | #endif /* __TI_CAL_H__ */ | ||
| @@ -34,19 +34,17 @@ · 33 unmodified lines | |||
| 34 | */ | 34 | */ |
| 35 | #define DRA72_CAL_PRE_ES2_LDO_DISABLE BIT(0) | 35 | #define DRA72_CAL_PRE_ES2_LDO_DISABLE BIT(0) |
| 36 | 36 | ||
| 37 | #define CAL_NUM_CSI2_PORTS 2 | ||
| 38 | |||
| 39 | /* CAL register offsets */ | 37 | /* CAL register offsets */ |
| 40 | 38 | ||
| 41 | #define CAL_HL_REVISION 0x0000 | 39 | #define CAL_HL_REVISION 0x0000 |
| 42 | #define CAL_HL_HWINFO 0x0004 | 40 | #define CAL_HL_HWINFO 0x0004 |
| 43 | #define CAL_HL_SYSCONFIG 0x0010 | 41 | #define CAL_HL_SYSCONFIG 0x0010 |
| 44 | #define CAL_HL_IRQ_EOI 0x001c | 42 | #define CAL_HL_IRQ_EOI 0x001c |
| 45 | #define CAL_HL_IRQSTATUS_RAW(m) (0x20U + ((m-1) * 0x10U)) | 43 | #define CAL_HL_IRQSTATUS_RAW(m) (0x20U + (m) * 0x10U) |
| 46 | #define CAL_HL_IRQSTATUS(m) (0x24U + ((m-1) * 0x10U)) | 44 | #define CAL_HL_IRQSTATUS(m) (0x24U + (m) * 0x10U) |
| 47 | #define CAL_HL_IRQENABLE_SET(m) (0x28U + ((m-1) * 0x10U)) | 45 | #define CAL_HL_IRQENABLE_SET(m) (0x28U + (m) * 0x10U) |
| 48 | #define CAL_HL_IRQENABLE_CLR(m) (0x2cU + ((m-1) * 0x10U)) | 46 | #define CAL_HL_IRQENABLE_CLR(m) (0x2cU + (m) * 0x10U) |
| 49 | #define CAL_PIX_PROC(m) (0xc0U + ((m-1) * 0x4U)) | 47 | #define CAL_PIX_PROC(m) (0xc0U + (m) * 0x4U) |
| 50 | #define CAL_CTRL 0x100 | 48 | #define CAL_CTRL 0x100 |
| 51 | #define CAL_CTRL1 0x104 | 49 | #define CAL_CTRL1 0x104 |
| 52 | #define CAL_LINE_NUMBER_EVT 0x108 | 50 | #define CAL_LINE_NUMBER_EVT 0x108 |
| @@ -62,34 +60,34 @@ · 9 unmodified lines | |||
| 62 | #define CAL_RD_DMA_INIT_ADDR 0x154 | 60 | #define CAL_RD_DMA_INIT_ADDR 0x154 |
| 63 | #define CAL_RD_DMA_INIT_OFST 0x168 | 61 | #define CAL_RD_DMA_INIT_OFST 0x168 |
| 64 | #define CAL_RD_DMA_CTRL2 0x16c | 62 | #define CAL_RD_DMA_CTRL2 0x16c |
| 65 | #define CAL_WR_DMA_CTRL(m) (0x200U + ((m-1) * 0x10U)) | 63 | #define CAL_WR_DMA_CTRL(m) (0x200U + (m) * 0x10U) |
| 66 | #define CAL_WR_DMA_ADDR(m) (0x204U + ((m-1) * 0x10U)) | 64 | #define CAL_WR_DMA_ADDR(m) (0x204U + (m) * 0x10U) |
| 67 | #define CAL_WR_DMA_OFST(m) (0x208U + ((m-1) * 0x10U)) | 65 | #define CAL_WR_DMA_OFST(m) (0x208U + (m) * 0x10U) |
| 68 | #define CAL_WR_DMA_XSIZE(m) (0x20cU + ((m-1) * 0x10U)) | 66 | #define CAL_WR_DMA_XSIZE(m) (0x20cU + (m) * 0x10U) |
| 69 | #define CAL_CSI2_PPI_CTRL(m) (0x300U + ((m-1) * 0x80U)) | 67 | #define CAL_CSI2_PPI_CTRL(m) (0x300U + (m) * 0x80U) |
| 70 | #define CAL_CSI2_COMPLEXIO_CFG(m) (0x304U + ((m-1) * 0x80U)) | 68 | #define CAL_CSI2_COMPLEXIO_CFG(m) (0x304U + (m) * 0x80U) |
| 71 | #define CAL_CSI2_COMPLEXIO_IRQSTATUS(m) (0x308U + ((m-1) * 0x80U)) | 69 | #define CAL_CSI2_COMPLEXIO_IRQSTATUS(m) (0x308U + (m) * 0x80U) |
| 72 | #define CAL_CSI2_SHORT_PACKET(m) (0x30cU + ((m-1) * 0x80U)) | 70 | #define CAL_CSI2_SHORT_PACKET(m) (0x30cU + (m) * 0x80U) |
| 73 | #define CAL_CSI2_COMPLEXIO_IRQENABLE(m) (0x310U + ((m-1) * 0x80U)) | 71 | #define CAL_CSI2_COMPLEXIO_IRQENABLE(m) (0x310U + (m) * 0x80U) |
| 74 | #define CAL_CSI2_TIMING(m) (0x314U + ((m-1) * 0x80U)) | 72 | #define CAL_CSI2_TIMING(m) (0x314U + (m) * 0x80U) |
| 75 | #define CAL_CSI2_VC_IRQENABLE(m) (0x318U + ((m-1) * 0x80U)) | 73 | #define CAL_CSI2_VC_IRQENABLE(m) (0x318U + (m) * 0x80U) |
| 76 | #define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + ((m-1) * 0x80U)) | 74 | #define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + (m) * 0x80U) |
| 77 | #define CAL_CSI2_CTX0(m) (0x330U + ((m-1) * 0x80U)) | 75 | #define CAL_CSI2_CTX0(m) (0x330U + (m) * 0x80U) |
| 78 | #define CAL_CSI2_CTX1(m) (0x334U + ((m-1) * 0x80U)) | 76 | #define CAL_CSI2_CTX1(m) (0x334U + (m) * 0x80U) |
| 79 | #define CAL_CSI2_CTX2(m) (0x338U + ((m-1) * 0x80U)) | 77 | #define CAL_CSI2_CTX2(m) (0x338U + (m) * 0x80U) |
| 80 | #define CAL_CSI2_CTX3(m) (0x33cU + ((m-1) * 0x80U)) | 78 | #define CAL_CSI2_CTX3(m) (0x33cU + (m) * 0x80U) |
| 81 | #define CAL_CSI2_CTX4(m) (0x340U + ((m-1) * 0x80U)) | 79 | #define CAL_CSI2_CTX4(m) (0x340U + (m) * 0x80U) |
| 82 | #define CAL_CSI2_CTX5(m) (0x344U + ((m-1) * 0x80U)) | 80 | #define CAL_CSI2_CTX5(m) (0x344U + (m) * 0x80U) |
| 83 | #define CAL_CSI2_CTX6(m) (0x348U + ((m-1) * 0x80U)) | 81 | #define CAL_CSI2_CTX6(m) (0x348U + (m) * 0x80U) |
| 84 | #define CAL_CSI2_CTX7(m) (0x34cU + ((m-1) * 0x80U)) | 82 | #define CAL_CSI2_CTX7(m) (0x34cU + (m) * 0x80U) |
| 85 | #define CAL_CSI2_STATUS0(m) (0x350U + ((m-1) * 0x80U)) | 83 | #define CAL_CSI2_STATUS0(m) (0x350U + (m) * 0x80U) |
| 86 | #define CAL_CSI2_STATUS1(m) (0x354U + ((m-1) * 0x80U)) | 84 | #define CAL_CSI2_STATUS1(m) (0x354U + (m) * 0x80U) |
| 87 | #define CAL_CSI2_STATUS2(m) (0x358U + ((m-1) * 0x80U)) | 85 | #define CAL_CSI2_STATUS2(m) (0x358U + (m) * 0x80U) |
| 88 | #define CAL_CSI2_STATUS3(m) (0x35cU + ((m-1) * 0x80U)) | 86 | #define CAL_CSI2_STATUS3(m) (0x35cU + (m) * 0x80U) |
| 89 | #define CAL_CSI2_STATUS4(m) (0x360U + ((m-1) * 0x80U)) | 87 | #define CAL_CSI2_STATUS4(m) (0x360U + (m) * 0x80U) |
| 90 | #define CAL_CSI2_STATUS5(m) (0x364U + ((m-1) * 0x80U)) | 88 | #define CAL_CSI2_STATUS5(m) (0x364U + (m) * 0x80U) |
| 91 | #define CAL_CSI2_STATUS6(m) (0x368U + ((m-1) * 0x80U)) | 89 | #define CAL_CSI2_STATUS6(m) (0x368U + (m) * 0x80U) |
| 92 | #define CAL_CSI2_STATUS7(m) (0x36cU + ((m-1) * 0x80U)) | 90 | #define CAL_CSI2_STATUS7(m) (0x36cU + (m) * 0x80U) |
| 93 | 91 | ||
| 94 | /* CAL CSI2 PHY register offsets */ | 92 | /* CAL CSI2 PHY register offsets */ |
| 95 | #define CAL_CSI2_PHY_REG0 0x000 | 93 | #define CAL_CSI2_PHY_REG0 0x000 |
| @@ -141,12 +139,12 @@ · 45 unmodified lines | |||
| 141 | #define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0 | 139 | #define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0 |
| 142 | #define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0 | 140 | #define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0 |
| 143 | 141 | ||
| 144 | #define CAL_HL_IRQ_MASK(m) BIT((m) - 1) | 142 | #define CAL_HL_IRQ_MASK(m) BIT(m) |
| 145 | 143 | ||
| 146 | #define CAL_HL_IRQ_OCPO_ERR_MASK BIT(6) | 144 | #define CAL_HL_IRQ_OCPO_ERR_MASK BIT(6) |
| 147 | 145 | ||
| 148 | #define CAL_HL_IRQ_CIO_MASK(i) BIT(16 + ((i) - 1) * 8) | 146 | #define CAL_HL_IRQ_CIO_MASK(i) BIT(16 + (i) * 8) |
| 149 | #define CAL_HL_IRQ_VC_MASK(i) BIT(17 + ((i) - 1) * 8) | 147 | #define CAL_HL_IRQ_VC_MASK(i) BIT(17 + (i) * 8) |
| 150 | 148 | ||
| 151 | #define CAL_PIX_PROC_EN_MASK BIT(0) | 149 | #define CAL_PIX_PROC_EN_MASK BIT(0) |
| 152 | #define CAL_PIX_PROC_EXTRACT_MASK GENMASK(4, 1) | 150 | #define CAL_PIX_PROC_EXTRACT_MASK GENMASK(4, 1) |
| @@ -1576,7 +1576,7 @@ static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) · 1575 unmodified lines | |||
| 1576 | 1576 | ||
| 1577 | *f = q_data->format; | 1577 | *f = q_data->format; |
| 1578 | 1578 | ||
| 1579 | if (!V4L2_TYPE_IS_OUTPUT(f->type)) { | 1579 | if (V4L2_TYPE_IS_CAPTURE(f->type)) { |
| 1580 | struct vpe_q_data *s_q_data; | 1580 | struct vpe_q_data *s_q_data; |
| 1581 | struct v4l2_pix_format_mplane *spix; | 1581 | struct v4l2_pix_format_mplane *spix; |
| 1582 | 1582 | ||
| @@ -431,6 +431,8 @@ vsp1_dl_cmd_pool_create(struct vsp1_device *vsp1, enum vsp1_extcmd_type type, · 430 unmodified lines | |||
| 431 | if (!pool) | 431 | if (!pool) |
| 432 | return NULL; | 432 | return NULL; |
| 433 | 433 | ||
| 434 | pool->vsp1 = vsp1; | ||
| 435 | |||
| 434 | spin_lock_init(&pool->lock); | 436 | spin_lock_init(&pool->lock); |
| 435 | INIT_LIST_HEAD(&pool->free); | 437 | INIT_LIST_HEAD(&pool->free); |
| 436 | 438 | ||
| @@ -12,6 +12,13 @@ config VIDEO_XILINX · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | if VIDEO_XILINX | 13 | if VIDEO_XILINX |
| 14 | 14 | ||
| 15 | config VIDEO_XILINX_CSI2RXSS | ||
| 16 | tristate "Xilinx CSI-2 Rx Subsystem" | ||
| 17 | help | ||
| 18 | Driver for Xilinx MIPI CSI-2 Rx Subsystem. This is a V4L sub-device | ||
| 19 | based driver that takes input from CSI-2 Tx source and converts | ||
| 20 | it into an AXI4-Stream. | ||
| 21 | |||
| 15 | config VIDEO_XILINX_TPG | 22 | config VIDEO_XILINX_TPG |
| 16 | tristate "Xilinx Video Test Pattern Generator" | 23 | tristate "Xilinx Video Test Pattern Generator" |
| 17 | depends on VIDEO_XILINX | 24 | depends on VIDEO_XILINX |
| @@ -3,5 +3,6 @@ · 2 unmodified lines | |||
| 3 | xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o | 3 | xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o | 5 | obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o |
| 6 | obj-$(CONFIG_VIDEO_XILINX_CSI2RXSS) += xilinx-csi2rxss.o | ||
| 6 | obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o | 7 | obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o |
| 7 | obj-$(CONFIG_VIDEO_XILINX_VTC) += xilinx-vtc.o | 8 | obj-$(CONFIG_VIDEO_XILINX_VTC) += xilinx-vtc.o |
| @@ -0,0 +1,1111 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Driver for Xilinx MIPI CSI-2 Rx Subsystem | ||
| 4 | * | ||
| 5 | * Copyright (C) 2016 - 2020 Xilinx, Inc. | ||
| 6 | * | ||
| 7 | * Contacts: Vishal Sagar <vishal.sagar@xilinx.com> | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | #include <linux/clk.h> | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/gpio/consumer.h> | ||
| 13 | #include <linux/interrupt.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/mutex.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | #include <linux/of_irq.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/v4l2-subdev.h> | ||
| 20 | #include <media/media-entity.h> | ||
| 21 | #include <media/v4l2-common.h> | ||
| 22 | #include <media/v4l2-ctrls.h> | ||
| 23 | #include <media/v4l2-fwnode.h> | ||
| 24 | #include <media/v4l2-subdev.h> | ||
| 25 | #include "xilinx-vip.h" | ||
| 26 | |||
| 27 | /* Register register map */ | ||
| 28 | #define XCSI_CCR_OFFSET 0x00 | ||
| 29 | #define XCSI_CCR_SOFTRESET BIT(1) | ||
| 30 | #define XCSI_CCR_ENABLE BIT(0) | ||
| 31 | |||
| 32 | #define XCSI_PCR_OFFSET 0x04 | ||
| 33 | #define XCSI_PCR_MAXLANES_MASK GENMASK(4, 3) | ||
| 34 | #define XCSI_PCR_ACTLANES_MASK GENMASK(1, 0) | ||
| 35 | |||
| 36 | #define XCSI_CSR_OFFSET 0x10 | ||
| 37 | #define XCSI_CSR_PKTCNT GENMASK(31, 16) | ||
| 38 | #define XCSI_CSR_SPFIFOFULL BIT(3) | ||
| 39 | #define XCSI_CSR_SPFIFONE BIT(2) | ||
| 40 | #define XCSI_CSR_SLBF BIT(1) | ||
| 41 | #define XCSI_CSR_RIPCD BIT(0) | ||
| 42 | |||
| 43 | #define XCSI_GIER_OFFSET 0x20 | ||
| 44 | #define XCSI_GIER_GIE BIT(0) | ||
| 45 | |||
| 46 | #define XCSI_ISR_OFFSET 0x24 | ||
| 47 | #define XCSI_IER_OFFSET 0x28 | ||
| 48 | |||
| 49 | #define XCSI_ISR_FR BIT(31) | ||
| 50 | #define XCSI_ISR_VCXFE BIT(30) | ||
| 51 | #define XCSI_ISR_WCC BIT(22) | ||
| 52 | #define XCSI_ISR_ILC BIT(21) | ||
| 53 | #define XCSI_ISR_SPFIFOF BIT(20) | ||
| 54 | #define XCSI_ISR_SPFIFONE BIT(19) | ||
| 55 | #define XCSI_ISR_SLBF BIT(18) | ||
| 56 | #define XCSI_ISR_STOP BIT(17) | ||
| 57 | #define XCSI_ISR_SOTERR BIT(13) | ||
| 58 | #define XCSI_ISR_SOTSYNCERR BIT(12) | ||
| 59 | #define XCSI_ISR_ECC2BERR BIT(11) | ||
| 60 | #define XCSI_ISR_ECC1BERR BIT(10) | ||
| 61 | #define XCSI_ISR_CRCERR BIT(9) | ||
| 62 | #define XCSI_ISR_DATAIDERR BIT(8) | ||
| 63 | #define XCSI_ISR_VC3FSYNCERR BIT(7) | ||
| 64 | #define XCSI_ISR_VC3FLVLERR BIT(6) | ||
| 65 | #define XCSI_ISR_VC2FSYNCERR BIT(5) | ||
| 66 | #define XCSI_ISR_VC2FLVLERR BIT(4) | ||
| 67 | #define XCSI_ISR_VC1FSYNCERR BIT(3) | ||
| 68 | #define XCSI_ISR_VC1FLVLERR BIT(2) | ||
| 69 | #define XCSI_ISR_VC0FSYNCERR BIT(1) | ||
| 70 | #define XCSI_ISR_VC0FLVLERR BIT(0) | ||
| 71 | |||
| 72 | #define XCSI_ISR_ALLINTR_MASK (0xc07e3fff) | ||
| 73 | |||
| 74 | /* | ||
| 75 | * Removed VCXFE mask as it doesn't exist in IER | ||
| 76 | * Removed STOP state irq as this will keep driver in irq handler only | ||
| 77 | */ | ||
| 78 | #define XCSI_IER_INTR_MASK (XCSI_ISR_ALLINTR_MASK &\ | ||
| 79 | ~(XCSI_ISR_STOP | XCSI_ISR_VCXFE)) | ||
| 80 | |||
| 81 | #define XCSI_SPKTR_OFFSET 0x30 | ||
| 82 | #define XCSI_SPKTR_DATA GENMASK(23, 8) | ||
| 83 | #define XCSI_SPKTR_VC GENMASK(7, 6) | ||
| 84 | #define XCSI_SPKTR_DT GENMASK(5, 0) | ||
| 85 | #define XCSI_SPKT_FIFO_DEPTH 31 | ||
| 86 | |||
| 87 | #define XCSI_VCXR_OFFSET 0x34 | ||
| 88 | #define XCSI_VCXR_VCERR GENMASK(23, 0) | ||
| 89 | #define XCSI_VCXR_FSYNCERR BIT(1) | ||
| 90 | #define XCSI_VCXR_FLVLERR BIT(0) | ||
| 91 | |||
| 92 | #define XCSI_CLKINFR_OFFSET 0x3C | ||
| 93 | #define XCSI_CLKINFR_STOP BIT(1) | ||
| 94 | |||
| 95 | #define XCSI_DLXINFR_OFFSET 0x40 | ||
| 96 | #define XCSI_DLXINFR_STOP BIT(5) | ||
| 97 | #define XCSI_DLXINFR_SOTERR BIT(1) | ||
| 98 | #define XCSI_DLXINFR_SOTSYNCERR BIT(0) | ||
| 99 | #define XCSI_MAXDL_COUNT 0x4 | ||
| 100 | |||
| 101 | #define XCSI_VCXINF1R_OFFSET 0x60 | ||
| 102 | #define XCSI_VCXINF1R_LINECOUNT GENMASK(31, 16) | ||
| 103 | #define XCSI_VCXINF1R_LINECOUNT_SHIFT 16 | ||
| 104 | #define XCSI_VCXINF1R_BYTECOUNT GENMASK(15, 0) | ||
| 105 | |||
| 106 | #define XCSI_VCXINF2R_OFFSET 0x64 | ||
| 107 | #define XCSI_VCXINF2R_DT GENMASK(5, 0) | ||
| 108 | #define XCSI_MAXVCX_COUNT 16 | ||
| 109 | |||
| 110 | /* | ||
| 111 | * Sink pad connected to sensor source pad. | ||
| 112 | * Source pad connected to next module like demosaic. | ||
| 113 | */ | ||
| 114 | #define XCSI_MEDIA_PADS 2 | ||
| 115 | #define XCSI_DEFAULT_WIDTH 1920 | ||
| 116 | #define XCSI_DEFAULT_HEIGHT 1080 | ||
| 117 | |||
| 118 | /* MIPI CSI-2 Data Types from spec */ | ||
| 119 | #define XCSI_DT_YUV4228B 0x1e | ||
| 120 | #define XCSI_DT_YUV42210B 0x1f | ||
| 121 | #define XCSI_DT_RGB444 0x20 | ||
| 122 | #define XCSI_DT_RGB555 0x21 | ||
| 123 | #define XCSI_DT_RGB565 0x22 | ||
| 124 | #define XCSI_DT_RGB666 0x23 | ||
| 125 | #define XCSI_DT_RGB888 0x24 | ||
| 126 | #define XCSI_DT_RAW6 0x28 | ||
| 127 | #define XCSI_DT_RAW7 0x29 | ||
| 128 | #define XCSI_DT_RAW8 0x2a | ||
| 129 | #define XCSI_DT_RAW10 0x2b | ||
| 130 | #define XCSI_DT_RAW12 0x2c | ||
| 131 | #define XCSI_DT_RAW14 0x2d | ||
| 132 | #define XCSI_DT_RAW16 0x2e | ||
| 133 | #define XCSI_DT_RAW20 0x2f | ||
| 134 | |||
| 135 | #define XCSI_VCX_START 4 | ||
| 136 | #define XCSI_MAX_VC 4 | ||
| 137 | #define XCSI_MAX_VCX 16 | ||
| 138 | |||
| 139 | #define XCSI_NEXTREG_OFFSET 4 | ||
| 140 | |||
| 141 | /* There are 2 events frame sync and frame level error per VC */ | ||
| 142 | #define XCSI_VCX_NUM_EVENTS ((XCSI_MAX_VCX - XCSI_MAX_VC) * 2) | ||
| 143 | |||
| 144 | /** | ||
| 145 | * struct xcsi2rxss_event - Event log structure | ||
| 146 | * @mask: Event mask | ||
| 147 | * @name: Name of the event | ||
| 148 | */ | ||
| 149 | struct xcsi2rxss_event { | ||
| 150 | u32 mask; | ||
| 151 | const char *name; | ||
| 152 | }; | ||
| 153 | |||
| 154 | static const struct xcsi2rxss_event xcsi2rxss_events[] = { | ||
| 155 | { XCSI_ISR_FR, "Frame Received" }, | ||
| 156 | { XCSI_ISR_VCXFE, "VCX Frame Errors" }, | ||
| 157 | { XCSI_ISR_WCC, "Word Count Errors" }, | ||
| 158 | { XCSI_ISR_ILC, "Invalid Lane Count Error" }, | ||
| 159 | { XCSI_ISR_SPFIFOF, "Short Packet FIFO OverFlow Error" }, | ||
| 160 | { XCSI_ISR_SPFIFONE, "Short Packet FIFO Not Empty" }, | ||
| 161 | { XCSI_ISR_SLBF, "Streamline Buffer Full Error" }, | ||
| 162 | { XCSI_ISR_STOP, "Lane Stop State" }, | ||
| 163 | { XCSI_ISR_SOTERR, "SOT Error" }, | ||
| 164 | { XCSI_ISR_SOTSYNCERR, "SOT Sync Error" }, | ||
| 165 | { XCSI_ISR_ECC2BERR, "2 Bit ECC Unrecoverable Error" }, | ||
| 166 | { XCSI_ISR_ECC1BERR, "1 Bit ECC Recoverable Error" }, | ||
| 167 | { XCSI_ISR_CRCERR, "CRC Error" }, | ||
| 168 | { XCSI_ISR_DATAIDERR, "Data Id Error" }, | ||
| 169 | { XCSI_ISR_VC3FSYNCERR, "Virtual Channel 3 Frame Sync Error" }, | ||
| 170 | { XCSI_ISR_VC3FLVLERR, "Virtual Channel 3 Frame Level Error" }, | ||
| 171 | { XCSI_ISR_VC2FSYNCERR, "Virtual Channel 2 Frame Sync Error" }, | ||
| 172 | { XCSI_ISR_VC2FLVLERR, "Virtual Channel 2 Frame Level Error" }, | ||
| 173 | { XCSI_ISR_VC1FSYNCERR, "Virtual Channel 1 Frame Sync Error" }, | ||
| 174 | { XCSI_ISR_VC1FLVLERR, "Virtual Channel 1 Frame Level Error" }, | ||
| 175 | { XCSI_ISR_VC0FSYNCERR, "Virtual Channel 0 Frame Sync Error" }, | ||
| 176 | { XCSI_ISR_VC0FLVLERR, "Virtual Channel 0 Frame Level Error" } | ||
| 177 | }; | ||
| 178 | |||
| 179 | #define XCSI_NUM_EVENTS ARRAY_SIZE(xcsi2rxss_events) | ||
| 180 | |||
| 181 | /* | ||
| 182 | * This table provides a mapping between CSI-2 Data type | ||
| 183 | * and media bus formats | ||
| 184 | */ | ||
| 185 | static const u32 xcsi2dt_mbus_lut[][2] = { | ||
| 186 | { XCSI_DT_YUV4228B, MEDIA_BUS_FMT_UYVY8_1X16 }, | ||
| 187 | { XCSI_DT_YUV42210B, MEDIA_BUS_FMT_UYVY10_1X20 }, | ||
| 188 | { XCSI_DT_RGB444, 0 }, | ||
| 189 | { XCSI_DT_RGB555, 0 }, | ||
| 190 | { XCSI_DT_RGB565, 0 }, | ||
| 191 | { XCSI_DT_RGB666, 0 }, | ||
| 192 | { XCSI_DT_RGB888, MEDIA_BUS_FMT_RBG888_1X24 }, | ||
| 193 | { XCSI_DT_RAW6, 0 }, | ||
| 194 | { XCSI_DT_RAW7, 0 }, | ||
| 195 | { XCSI_DT_RAW8, MEDIA_BUS_FMT_SRGGB8_1X8 }, | ||
| 196 | { XCSI_DT_RAW8, MEDIA_BUS_FMT_SBGGR8_1X8 }, | ||
| 197 | { XCSI_DT_RAW8, MEDIA_BUS_FMT_SGBRG8_1X8 }, | ||
| 198 | { XCSI_DT_RAW8, MEDIA_BUS_FMT_SGRBG8_1X8 }, | ||
| 199 | { XCSI_DT_RAW10, MEDIA_BUS_FMT_SRGGB10_1X10 }, | ||
| 200 | { XCSI_DT_RAW10, MEDIA_BUS_FMT_SBGGR10_1X10 }, | ||
| 201 | { XCSI_DT_RAW10, MEDIA_BUS_FMT_SGBRG10_1X10 }, | ||
| 202 | { XCSI_DT_RAW10, MEDIA_BUS_FMT_SGRBG10_1X10 }, | ||
| 203 | { XCSI_DT_RAW12, MEDIA_BUS_FMT_SRGGB12_1X12 }, | ||
| 204 | { XCSI_DT_RAW12, MEDIA_BUS_FMT_SBGGR12_1X12 }, | ||
| 205 | { XCSI_DT_RAW12, MEDIA_BUS_FMT_SGBRG12_1X12 }, | ||
| 206 | { XCSI_DT_RAW12, MEDIA_BUS_FMT_SGRBG12_1X12 }, | ||
| 207 | { XCSI_DT_RAW16, MEDIA_BUS_FMT_SRGGB16_1X16 }, | ||
| 208 | { XCSI_DT_RAW16, MEDIA_BUS_FMT_SBGGR16_1X16 }, | ||
| 209 | { XCSI_DT_RAW16, MEDIA_BUS_FMT_SGBRG16_1X16 }, | ||
| 210 | { XCSI_DT_RAW16, MEDIA_BUS_FMT_SGRBG16_1X16 }, | ||
| 211 | { XCSI_DT_RAW20, 0 }, | ||
| 212 | }; | ||
| 213 | |||
| 214 | /** | ||
| 215 | * struct xcsi2rxss_state - CSI-2 Rx Subsystem device structure | ||
| 216 | * @subdev: The v4l2 subdev structure | ||
| 217 | * @format: Active V4L2 formats on each pad | ||
| 218 | * @default_format: Default V4L2 format | ||
| 219 | * @events: counter for events | ||
| 220 | * @vcx_events: counter for vcx_events | ||
| 221 | * @dev: Platform structure | ||
| 222 | * @rsubdev: Remote subdev connected to sink pad | ||
| 223 | * @rst_gpio: reset to video_aresetn | ||
| 224 | * @clks: array of clocks | ||
| 225 | * @iomem: Base address of subsystem | ||
| 226 | * @max_num_lanes: Maximum number of lanes present | ||
| 227 | * @datatype: Data type filter | ||
| 228 | * @lock: mutex for accessing this structure | ||
| 229 | * @pads: media pads | ||
| 230 | * @streaming: Flag for storing streaming state | ||
| 231 | * @enable_active_lanes: If number of active lanes can be modified | ||
| 232 | * @en_vcx: If more than 4 VC are enabled | ||
| 233 | * | ||
| 234 | * This structure contains the device driver related parameters | ||
| 235 | */ | ||
| 236 | struct xcsi2rxss_state { | ||
| 237 | struct v4l2_subdev subdev; | ||
| 238 | struct v4l2_mbus_framefmt format; | ||
| 239 | struct v4l2_mbus_framefmt default_format; | ||
| 240 | u32 events[XCSI_NUM_EVENTS]; | ||
| 241 | u32 vcx_events[XCSI_VCX_NUM_EVENTS]; | ||
| 242 | struct device *dev; | ||
| 243 | struct v4l2_subdev *rsubdev; | ||
| 244 | struct gpio_desc *rst_gpio; | ||
| 245 | struct clk_bulk_data *clks; | ||
| 246 | void __iomem *iomem; | ||
| 247 | u32 max_num_lanes; | ||
| 248 | u32 datatype; | ||
| 249 | /* used to protect access to this struct */ | ||
| 250 | struct mutex lock; | ||
| 251 | struct media_pad pads[XCSI_MEDIA_PADS]; | ||
| 252 | bool streaming; | ||
| 253 | bool enable_active_lanes; | ||
| 254 | bool en_vcx; | ||
| 255 | }; | ||
| 256 | |||
| 257 | static const struct clk_bulk_data xcsi2rxss_clks[] = { | ||
| 258 | { .id = "lite_aclk" }, | ||
| 259 | { .id = "video_aclk" }, | ||
| 260 | }; | ||
| 261 | |||
| 262 | static inline struct xcsi2rxss_state * | ||
| 263 | to_xcsi2rxssstate(struct v4l2_subdev *subdev) | ||
| 264 | { | ||
| 265 | return container_of(subdev, struct xcsi2rxss_state, subdev); | ||
| 266 | } | ||
| 267 | |||
| 268 | /* | ||
| 269 | * Register related operations | ||
| 270 | */ | ||
| 271 | static inline u32 xcsi2rxss_read(struct xcsi2rxss_state *xcsi2rxss, u32 addr) | ||
| 272 | { | ||
| 273 | return ioread32(xcsi2rxss->iomem + addr); | ||
| 274 | } | ||
| 275 | |||
| 276 | static inline void xcsi2rxss_write(struct xcsi2rxss_state *xcsi2rxss, u32 addr, | ||
| 277 | u32 value) | ||
| 278 | { | ||
| 279 | iowrite32(value, xcsi2rxss->iomem + addr); | ||
| 280 | } | ||
| 281 | |||
| 282 | static inline void xcsi2rxss_clr(struct xcsi2rxss_state *xcsi2rxss, u32 addr, | ||
| 283 | u32 clr) | ||
| 284 | { | ||
| 285 | xcsi2rxss_write(xcsi2rxss, addr, | ||
| 286 | xcsi2rxss_read(xcsi2rxss, addr) & ~clr); | ||
| 287 | } | ||
| 288 | |||
| 289 | static inline void xcsi2rxss_set(struct xcsi2rxss_state *xcsi2rxss, u32 addr, | ||
| 290 | u32 set) | ||
| 291 | { | ||
| 292 | xcsi2rxss_write(xcsi2rxss, addr, xcsi2rxss_read(xcsi2rxss, addr) | set); | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 296 | * This function returns the nth mbus for a data type. | ||
| 297 | * In case of error, mbus code returned is 0. | ||
| 298 | */ | ||
| 299 | static u32 xcsi2rxss_get_nth_mbus(u32 dt, u32 n) | ||
| 300 | { | ||
| 301 | unsigned int i; | ||
| 302 | |||
| 303 | for (i = 0; i < ARRAY_SIZE(xcsi2dt_mbus_lut); i++) { | ||
| 304 | if (xcsi2dt_mbus_lut[i][0] == dt) { | ||
| 305 | if (n-- == 0) | ||
| 306 | return xcsi2dt_mbus_lut[i][1]; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | |||
| 313 | /* This returns the data type for a media bus format else 0 */ | ||
| 314 | static u32 xcsi2rxss_get_dt(u32 mbus) | ||
| 315 | { | ||
| 316 | unsigned int i; | ||
| 317 | |||
| 318 | for (i = 0; i < ARRAY_SIZE(xcsi2dt_mbus_lut); i++) { | ||
| 319 | if (xcsi2dt_mbus_lut[i][1] == mbus) | ||
| 320 | return xcsi2dt_mbus_lut[i][0]; | ||
| 321 | } | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | /** | ||
| 327 | * xcsi2rxss_soft_reset - Does a soft reset of the MIPI CSI-2 Rx Subsystem | ||
| 328 | * @state: Xilinx CSI-2 Rx Subsystem structure pointer | ||
| 329 | * | ||
| 330 | * Core takes less than 100 video clock cycles to reset. | ||
| 331 | * So a larger timeout value is chosen for margin. | ||
| 332 | * | ||
| 333 | * Return: 0 - on success OR -ETIME if reset times out | ||
| 334 | */ | ||
| 335 | static int xcsi2rxss_soft_reset(struct xcsi2rxss_state *state) | ||
| 336 | { | ||
| 337 | u32 timeout = 1000; /* us */ | ||
| 338 | |||
| 339 | xcsi2rxss_set(state, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET); | ||
| 340 | |||
| 341 | while (xcsi2rxss_read(state, XCSI_CSR_OFFSET) & XCSI_CSR_RIPCD) { | ||
| 342 | if (timeout == 0) { | ||
| 343 | dev_err(state->dev, "soft reset timed out!\n"); | ||
| 344 | return -ETIME; | ||
| 345 | } | ||
| 346 | |||
| 347 | timeout--; | ||
| 348 | udelay(1); | ||
| 349 | } | ||
| 350 | |||
| 351 | xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET); | ||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | |||
| 355 | static void xcsi2rxss_hard_reset(struct xcsi2rxss_state *state) | ||
| 356 | { | ||
| 357 | if (!state->rst_gpio) | ||
| 358 | return; | ||
| 359 | |||
| 360 | /* minimum of 40 dphy_clk_200M cycles */ | ||
| 361 | gpiod_set_value_cansleep(state->rst_gpio, 1); | ||
| 362 | usleep_range(1, 2); | ||
| 363 | gpiod_set_value_cansleep(state->rst_gpio, 0); | ||
| 364 | } | ||
| 365 | |||
| 366 | static void xcsi2rxss_reset_event_counters(struct xcsi2rxss_state *state) | ||
| 367 | { | ||
| 368 | unsigned int i; | ||
| 369 | |||
| 370 | for (i = 0; i < XCSI_NUM_EVENTS; i++) | ||
| 371 | state->events[i] = 0; | ||
| 372 | |||
| 373 | for (i = 0; i < XCSI_VCX_NUM_EVENTS; i++) | ||
| 374 | state->vcx_events[i] = 0; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* Print event counters */ | ||
| 378 | static void xcsi2rxss_log_counters(struct xcsi2rxss_state *state) | ||
| 379 | { | ||
| 380 | struct device *dev = state->dev; | ||
| 381 | unsigned int i; | ||
| 382 | |||
| 383 | for (i = 0; i < XCSI_NUM_EVENTS; i++) { | ||
| 384 | if (state->events[i] > 0) { | ||
| 385 | dev_info(dev, "%s events: %d\n", | ||
| 386 | xcsi2rxss_events[i].name, | ||
| 387 | state->events[i]); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | if (state->en_vcx) { | ||
| 392 | for (i = 0; i < XCSI_VCX_NUM_EVENTS; i++) { | ||
| 393 | if (state->vcx_events[i] > 0) { | ||
| 394 | dev_info(dev, | ||
| 395 | "VC %d Frame %s err vcx events: %d\n", | ||
| 396 | (i / 2) + XCSI_VCX_START, | ||
| 397 | i & 1 ? "Sync" : "Level", | ||
| 398 | state->vcx_events[i]); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /** | ||
| 405 | * xcsi2rxss_log_status - Logs the status of the CSI-2 Receiver | ||
| 406 | * @sd: Pointer to V4L2 subdevice structure | ||
| 407 | * | ||
| 408 | * This function prints the current status of Xilinx MIPI CSI-2 | ||
| 409 | * | ||
| 410 | * Return: 0 on success | ||
| 411 | */ | ||
| 412 | static int xcsi2rxss_log_status(struct v4l2_subdev *sd) | ||
| 413 | { | ||
| 414 | struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); | ||
| 415 | struct device *dev = xcsi2rxss->dev; | ||
| 416 | u32 reg, data; | ||
| 417 | unsigned int i, max_vc; | ||
| 418 | |||
| 419 | mutex_lock(&xcsi2rxss->lock); | ||
| 420 | |||
| 421 | xcsi2rxss_log_counters(xcsi2rxss); | ||
| 422 | |||
| 423 | dev_info(dev, "***** Core Status *****\n"); | ||
| 424 | data = xcsi2rxss_read(xcsi2rxss, XCSI_CSR_OFFSET); | ||
| 425 | dev_info(dev, "Short Packet FIFO Full = %s\n", | ||
| 426 | data & XCSI_CSR_SPFIFOFULL ? "true" : "false"); | ||
| 427 | dev_info(dev, "Short Packet FIFO Not Empty = %s\n", | ||
| 428 | data & XCSI_CSR_SPFIFONE ? "true" : "false"); | ||
| 429 | dev_info(dev, "Stream line buffer full = %s\n", | ||
| 430 | data & XCSI_CSR_SLBF ? "true" : "false"); | ||
| 431 | dev_info(dev, "Soft reset/Core disable in progress = %s\n", | ||
| 432 | data & XCSI_CSR_RIPCD ? "true" : "false"); | ||
| 433 | |||
| 434 | /* Clk & Lane Info */ | ||
| 435 | dev_info(dev, "******** Clock Lane Info *********\n"); | ||
| 436 | data = xcsi2rxss_read(xcsi2rxss, XCSI_CLKINFR_OFFSET); | ||
| 437 | dev_info(dev, "Clock Lane in Stop State = %s\n", | ||
| 438 | data & XCSI_CLKINFR_STOP ? "true" : "false"); | ||
| 439 | |||
| 440 | dev_info(dev, "******** Data Lane Info *********\n"); | ||
| 441 | dev_info(dev, "Lane\tSoT Error\tSoT Sync Error\tStop State\n"); | ||
| 442 | reg = XCSI_DLXINFR_OFFSET; | ||
| 443 | for (i = 0; i < XCSI_MAXDL_COUNT; i++) { | ||
| 444 | data = xcsi2rxss_read(xcsi2rxss, reg); | ||
| 445 | |||
| 446 | dev_info(dev, "%d\t%s\t\t%s\t\t%s\n", i, | ||
| 447 | data & XCSI_DLXINFR_SOTERR ? "true" : "false", | ||
| 448 | data & XCSI_DLXINFR_SOTSYNCERR ? "true" : "false", | ||
| 449 | data & XCSI_DLXINFR_STOP ? "true" : "false"); | ||
| 450 | |||
| 451 | reg += XCSI_NEXTREG_OFFSET; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* Virtual Channel Image Information */ | ||
| 455 | dev_info(dev, "********** Virtual Channel Info ************\n"); | ||
| 456 | dev_info(dev, "VC\tLine Count\tByte Count\tData Type\n"); | ||
| 457 | if (xcsi2rxss->en_vcx) | ||
| 458 | max_vc = XCSI_MAX_VCX; | ||
| 459 | else | ||
| 460 | max_vc = XCSI_MAX_VC; | ||
| 461 | |||
| 462 | reg = XCSI_VCXINF1R_OFFSET; | ||
| 463 | for (i = 0; i < max_vc; i++) { | ||
| 464 | u32 line_count, byte_count, data_type; | ||
| 465 | |||
| 466 | /* Get line and byte count from VCXINFR1 Register */ | ||
| 467 | data = xcsi2rxss_read(xcsi2rxss, reg); | ||
| 468 | byte_count = data & XCSI_VCXINF1R_BYTECOUNT; | ||
| 469 | line_count = data & XCSI_VCXINF1R_LINECOUNT; | ||
| 470 | line_count >>= XCSI_VCXINF1R_LINECOUNT_SHIFT; | ||
| 471 | |||
| 472 | /* Get data type from VCXINFR2 Register */ | ||
| 473 | reg += XCSI_NEXTREG_OFFSET; | ||
| 474 | data = xcsi2rxss_read(xcsi2rxss, reg); | ||
| 475 | data_type = data & XCSI_VCXINF2R_DT; | ||
| 476 | |||
| 477 | dev_info(dev, "%d\t%d\t\t%d\t\t0x%x\n", i, line_count, | ||
| 478 | byte_count, data_type); | ||
| 479 | |||
| 480 | /* Move to next pair of VC Info registers */ | ||
| 481 | reg += XCSI_NEXTREG_OFFSET; | ||
| 482 | } | ||
| 483 | |||
| 484 | mutex_unlock(&xcsi2rxss->lock); | ||
| 485 | |||
| 486 | return 0; | ||
| 487 | } | ||
| 488 | |||
| 489 | static struct v4l2_subdev *xcsi2rxss_get_remote_subdev(struct media_pad *local) | ||
| 490 | { | ||
| 491 | struct media_pad *remote; | ||
| 492 | |||
| 493 | remote = media_entity_remote_pad(local); | ||
| 494 | if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) | ||
| 495 | return NULL; | ||
| 496 | |||
| 497 | return media_entity_to_v4l2_subdev(remote->entity); | ||
| 498 | } | ||
| 499 | |||
| 500 | static int xcsi2rxss_start_stream(struct xcsi2rxss_state *state) | ||
| 501 | { | ||
| 502 | int ret = 0; | ||
| 503 | |||
| 504 | /* enable core */ | ||
| 505 | xcsi2rxss_set(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE); | ||
| 506 | |||
| 507 | ret = xcsi2rxss_soft_reset(state); | ||
| 508 | if (ret) { | ||
| 509 | state->streaming = false; | ||
| 510 | return ret; | ||
| 511 | } | ||
| 512 | |||
| 513 | /* enable interrupts */ | ||
| 514 | xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE); | ||
| 515 | xcsi2rxss_write(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK); | ||
| 516 | xcsi2rxss_set(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE); | ||
| 517 | |||
| 518 | state->streaming = true; | ||
| 519 | |||
| 520 | state->rsubdev = | ||
| 521 | xcsi2rxss_get_remote_subdev(&state->pads[XVIP_PAD_SINK]); | ||
| 522 | |||
| 523 | ret = v4l2_subdev_call(state->rsubdev, video, s_stream, 1); | ||
| 524 | if (ret) { | ||
| 525 | /* disable interrupts */ | ||
| 526 | xcsi2rxss_clr(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK); | ||
| 527 | xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE); | ||
| 528 | |||
| 529 | /* disable core */ | ||
| 530 | xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE); | ||
| 531 | state->streaming = false; | ||
| 532 | } | ||
| 533 | |||
| 534 | return ret; | ||
| 535 | } | ||
| 536 | |||
| 537 | static void xcsi2rxss_stop_stream(struct xcsi2rxss_state *state) | ||
| 538 | { | ||
| 539 | v4l2_subdev_call(state->rsubdev, video, s_stream, 0); | ||
| 540 | |||
| 541 | /* disable interrupts */ | ||
| 542 | xcsi2rxss_clr(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK); | ||
| 543 | xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE); | ||
| 544 | |||
| 545 | /* disable core */ | ||
| 546 | xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE); | ||
| 547 | state->streaming = false; | ||
| 548 | } | ||
| 549 | |||
| 550 | /** | ||
| 551 | * xcsi2rxss_irq_handler - Interrupt handler for CSI-2 | ||
| 552 | * @irq: IRQ number | ||
| 553 | * @data: Pointer to device state | ||
| 554 | * | ||
| 555 | * In the interrupt handler, a list of event counters are updated for | ||
| 556 | * corresponding interrupts. This is useful to get status / debug. | ||
| 557 | * | ||
| 558 | * Return: IRQ_HANDLED after handling interrupts | ||
| 559 | */ | ||
| 560 | static irqreturn_t xcsi2rxss_irq_handler(int irq, void *data) | ||
| 561 | { | ||
| 562 | struct xcsi2rxss_state *state = (struct xcsi2rxss_state *)data; | ||
| 563 | struct device *dev = state->dev; | ||
| 564 | u32 status; | ||
| 565 | |||
| 566 | status = xcsi2rxss_read(state, XCSI_ISR_OFFSET) & XCSI_ISR_ALLINTR_MASK; | ||
| 567 | xcsi2rxss_write(state, XCSI_ISR_OFFSET, status); | ||
| 568 | |||
| 569 | /* Received a short packet */ | ||
| 570 | if (status & XCSI_ISR_SPFIFONE) { | ||
| 571 | u32 count = 0; | ||
| 572 | |||
| 573 | /* | ||
| 574 | * Drain generic short packet FIFO by reading max 31 | ||
| 575 | * (fifo depth) short packets from fifo or till fifo is empty. | ||
| 576 | */ | ||
| 577 | for (count = 0; count < XCSI_SPKT_FIFO_DEPTH; ++count) { | ||
| 578 | u32 spfifostat, spkt; | ||
| 579 | |||
| 580 | spkt = xcsi2rxss_read(state, XCSI_SPKTR_OFFSET); | ||
| 581 | dev_dbg(dev, "Short packet = 0x%08x\n", spkt); | ||
| 582 | spfifostat = xcsi2rxss_read(state, XCSI_ISR_OFFSET); | ||
| 583 | spfifostat &= XCSI_ISR_SPFIFONE; | ||
| 584 | if (!spfifostat) | ||
| 585 | break; | ||
| 586 | xcsi2rxss_write(state, XCSI_ISR_OFFSET, spfifostat); | ||
| 587 | } | ||
| 588 | } | ||
| 589 | |||
| 590 | /* Short packet FIFO overflow */ | ||
| 591 | if (status & XCSI_ISR_SPFIFOF) | ||
| 592 | dev_dbg_ratelimited(dev, "Short packet FIFO overflowed\n"); | ||
| 593 | |||
| 594 | /* | ||
| 595 | * Stream line buffer full | ||
| 596 | * This means there is a backpressure from downstream IP | ||
| 597 | */ | ||
| 598 | if (status & XCSI_ISR_SLBF) { | ||
| 599 | dev_alert_ratelimited(dev, "Stream Line Buffer Full!\n"); | ||
| 600 | |||
| 601 | /* disable interrupts */ | ||
| 602 | xcsi2rxss_clr(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK); | ||
| 603 | xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE); | ||
| 604 | |||
| 605 | /* disable core */ | ||
| 606 | xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE); | ||
| 607 | |||
| 608 | /* | ||
| 609 | * The IP needs to be hard reset before it can be used now. | ||
| 610 | * This will be done in streamoff. | ||
| 611 | */ | ||
| 612 | |||
| 613 | /* | ||
| 614 | * TODO: Notify the whole pipeline with v4l2_subdev_notify() to | ||
| 615 | * inform userspace. | ||
| 616 | */ | ||
| 617 | } | ||
| 618 | |||
| 619 | /* Increment event counters */ | ||
| 620 | if (status & XCSI_ISR_ALLINTR_MASK) { | ||
| 621 | unsigned int i; | ||
| 622 | |||
| 623 | for (i = 0; i < XCSI_NUM_EVENTS; i++) { | ||
| 624 | if (!(status & xcsi2rxss_events[i].mask)) | ||
| 625 | continue; | ||
| 626 | state->events[i]++; | ||
| 627 | dev_dbg_ratelimited(dev, "%s: %u\n", | ||
| 628 | xcsi2rxss_events[i].name, | ||
| 629 | state->events[i]); | ||
| 630 | } | ||
| 631 | |||
| 632 | if (status & XCSI_ISR_VCXFE && state->en_vcx) { | ||
| 633 | u32 vcxstatus; | ||
| 634 | |||
| 635 | vcxstatus = xcsi2rxss_read(state, XCSI_VCXR_OFFSET); | ||
| 636 | vcxstatus &= XCSI_VCXR_VCERR; | ||
| 637 | for (i = 0; i < XCSI_VCX_NUM_EVENTS; i++) { | ||
| 638 | if (!(vcxstatus & BIT(i))) | ||
| 639 | continue; | ||
| 640 | state->vcx_events[i]++; | ||
| 641 | } | ||
| 642 | xcsi2rxss_write(state, XCSI_VCXR_OFFSET, vcxstatus); | ||
| 643 | } | ||
| 644 | } | ||
| 645 | |||
| 646 | return IRQ_HANDLED; | ||
| 647 | } | ||
| 648 | |||
| 649 | /** | ||
| 650 | * xcsi2rxss_s_stream - It is used to start/stop the streaming. | ||
| 651 | * @sd: V4L2 Sub device | ||
| 652 | * @enable: Flag (True / False) | ||
| 653 | * | ||
| 654 | * This function controls the start or stop of streaming for the | ||
| 655 | * Xilinx MIPI CSI-2 Rx Subsystem. | ||
| 656 | * | ||
| 657 | * Return: 0 on success, errors otherwise | ||
| 658 | */ | ||
| 659 | static int xcsi2rxss_s_stream(struct v4l2_subdev *sd, int enable) | ||
| 660 | { | ||
| 661 | struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); | ||
| 662 | int ret = 0; | ||
| 663 | |||
| 664 | mutex_lock(&xcsi2rxss->lock); | ||
| 665 | |||
| 666 | if (enable == xcsi2rxss->streaming) | ||
| 667 | goto stream_done; | ||
| 668 | |||
| 669 | if (enable) { | ||
| 670 | xcsi2rxss_reset_event_counters(xcsi2rxss); | ||
| 671 | ret = xcsi2rxss_start_stream(xcsi2rxss); | ||
| 672 | } else { | ||
| 673 | xcsi2rxss_stop_stream(xcsi2rxss); | ||
| 674 | xcsi2rxss_hard_reset(xcsi2rxss); | ||
| 675 | } | ||
| 676 | |||
| 677 | stream_done: | ||
| 678 | mutex_unlock(&xcsi2rxss->lock); | ||
| 679 | return ret; | ||
| 680 | } | ||
| 681 | |||
| 682 | static struct v4l2_mbus_framefmt * | ||
| 683 | __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss, | ||
| 684 | struct v4l2_subdev_pad_config *cfg, | ||
| 685 | unsigned int pad, u32 which) | ||
| 686 | { | ||
| 687 | switch (which) { | ||
| 688 | case V4L2_SUBDEV_FORMAT_TRY: | ||
| 689 | return v4l2_subdev_get_try_format(&xcsi2rxss->subdev, cfg, pad); | ||
| 690 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
| 691 | return &xcsi2rxss->format; | ||
| 692 | default: | ||
| 693 | return NULL; | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | /** | ||
| 698 | * xcsi2rxss_init_cfg - Initialise the pad format config to default | ||
| 699 | * @sd: Pointer to V4L2 Sub device structure | ||
| 700 | * @cfg: Pointer to sub device pad information structure | ||
| 701 | * | ||
| 702 | * This function is used to initialize the pad format with the default | ||
| 703 | * values. | ||
| 704 | * | ||
| 705 | * Return: 0 on success | ||
| 706 | */ | ||
| 707 | static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd, | ||
| 708 | struct v4l2_subdev_pad_config *cfg) | ||
| 709 | { | ||
| 710 | struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); | ||
| 711 | struct v4l2_mbus_framefmt *format; | ||
| 712 | unsigned int i; | ||
| 713 | |||
| 714 | mutex_lock(&xcsi2rxss->lock); | ||
| 715 | for (i = 0; i < XCSI_MEDIA_PADS; i++) { | ||
| 716 | format = v4l2_subdev_get_try_format(sd, cfg, i); | ||
| 717 | *format = xcsi2rxss->default_format; | ||
| 718 | } | ||
| 719 | mutex_unlock(&xcsi2rxss->lock); | ||
| 720 | |||
| 721 | return 0; | ||
| 722 | } | ||
| 723 | |||
| 724 | /** | ||
| 725 | * xcsi2rxss_get_format - Get the pad format | ||
| 726 | * @sd: Pointer to V4L2 Sub device structure | ||
| 727 | * @cfg: Pointer to sub device pad information structure | ||
| 728 | * @fmt: Pointer to pad level media bus format | ||
| 729 | * | ||
| 730 | * This function is used to get the pad format information. | ||
| 731 | * | ||
| 732 | * Return: 0 on success | ||
| 733 | */ | ||
| 734 | static int xcsi2rxss_get_format(struct v4l2_subdev *sd, | ||
| 735 | struct v4l2_subdev_pad_config *cfg, | ||
| 736 | struct v4l2_subdev_format *fmt) | ||
| 737 | { | ||
| 738 | struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); | ||
| 739 | |||
| 740 | mutex_lock(&xcsi2rxss->lock); | ||
| 741 | fmt->format = *__xcsi2rxss_get_pad_format(xcsi2rxss, cfg, fmt->pad, | ||
| 742 | fmt->which); | ||
| 743 | mutex_unlock(&xcsi2rxss->lock); | ||
| 744 | |||
| 745 | return 0; | ||
| 746 | } | ||
| 747 | |||
| 748 | /** | ||
| 749 | * xcsi2rxss_set_format - This is used to set the pad format | ||
| 750 | * @sd: Pointer to V4L2 Sub device structure | ||
| 751 | * @cfg: Pointer to sub device pad information structure | ||
| 752 | * @fmt: Pointer to pad level media bus format | ||
| 753 | * | ||
| 754 | * This function is used to set the pad format. Since the pad format is fixed | ||
| 755 | * in hardware, it can't be modified on run time. So when a format set is | ||
| 756 | * requested by application, all parameters except the format type is saved | ||
| 757 | * for the pad and the original pad format is sent back to the application. | ||
| 758 | * | ||
| 759 | * Return: 0 on success | ||
| 760 | */ | ||
| 761 | static int xcsi2rxss_set_format(struct v4l2_subdev *sd, | ||
| 762 | struct v4l2_subdev_pad_config *cfg, | ||
| 763 | struct v4l2_subdev_format *fmt) | ||
| 764 | { | ||
| 765 | struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd); | ||
| 766 | struct v4l2_mbus_framefmt *__format; | ||
| 767 | u32 dt; | ||
| 768 | |||
| 769 | mutex_lock(&xcsi2rxss->lock); | ||
| 770 | |||
| 771 | /* | ||
| 772 | * Only the format->code parameter matters for CSI as the | ||
| 773 | * CSI format cannot be changed at runtime. | ||
| 774 | * Ensure that format to set is copied to over to CSI pad format | ||
| 775 | */ | ||
| 776 | __format = __xcsi2rxss_get_pad_format(xcsi2rxss, cfg, | ||
| 777 | fmt->pad, fmt->which); | ||
| 778 | |||
| 779 | /* only sink pad format can be updated */ | ||
| 780 | if (fmt->pad == XVIP_PAD_SOURCE) { | ||
| 781 | fmt->format = *__format; | ||
| 782 | mutex_unlock(&xcsi2rxss->lock); | ||
| 783 | return 0; | ||
| 784 | } | ||
| 785 | |||
| 786 | /* | ||
| 787 | * RAW8 is supported in all datatypes. So if requested media bus format | ||
| 788 | * is of RAW8 type, then allow to be set. In case core is configured to | ||
| 789 | * other RAW, YUV422 8/10 or RGB888, set appropriate media bus format. | ||
| 790 | */ | ||
| 791 | dt = xcsi2rxss_get_dt(fmt->format.code); | ||
| 792 | if (dt != xcsi2rxss->datatype && dt != XCSI_DT_RAW8) { | ||
| 793 | dev_dbg(xcsi2rxss->dev, "Unsupported media bus format"); | ||
| 794 | /* set the default format for the data type */ | ||
| 795 | fmt->format.code = xcsi2rxss_get_nth_mbus(xcsi2rxss->datatype, | ||
| 796 | 0); | ||
| 797 | } | ||
| 798 | |||
| 799 | *__format = fmt->format; | ||
| 800 | mutex_unlock(&xcsi2rxss->lock); | ||
| 801 | |||
| 802 | return 0; | ||
| 803 | } | ||
| 804 | |||
| 805 | /* | ||
| 806 | * xcsi2rxss_enum_mbus_code - Handle pixel format enumeration | ||
| 807 | * @sd: pointer to v4l2 subdev structure | ||
| 808 | * @cfg: V4L2 subdev pad configuration | ||
| 809 | * @code: pointer to v4l2_subdev_mbus_code_enum structure | ||
| 810 | * | ||
| 811 | * Return: -EINVAL or zero on success | ||
| 812 | */ | ||
| 813 | static int xcsi2rxss_enum_mbus_code(struct v4l2_subdev *sd, | ||
| 814 | struct v4l2_subdev_pad_config *cfg, | ||
| 815 | struct v4l2_subdev_mbus_code_enum *code) | ||
| 816 | { | ||
| 817 | struct xcsi2rxss_state *state = to_xcsi2rxssstate(sd); | ||
| 818 | u32 dt, n; | ||
| 819 | int ret = 0; | ||
| 820 | |||
| 821 | /* RAW8 dt packets are available in all DT configurations */ | ||
| 822 | if (code->index < 4) { | ||
| 823 | n = code->index; | ||
| 824 | dt = XCSI_DT_RAW8; | ||
| 825 | } else if (state->datatype != XCSI_DT_RAW8) { | ||
| 826 | n = code->index - 4; | ||
| 827 | dt = state->datatype; | ||
| 828 | } else { | ||
| 829 | return -EINVAL; | ||
| 830 | } | ||
| 831 | |||
| 832 | code->code = xcsi2rxss_get_nth_mbus(dt, n); | ||
| 833 | if (!code->code) | ||
| 834 | ret = -EINVAL; | ||
| 835 | |||
| 836 | return ret; | ||
| 837 | } | ||
| 838 | |||
| 839 | /* ----------------------------------------------------------------------------- | ||
| 840 | * Media Operations | ||
| 841 | */ | ||
| 842 | |||
| 843 | static const struct media_entity_operations xcsi2rxss_media_ops = { | ||
| 844 | .link_validate = v4l2_subdev_link_validate | ||
| 845 | }; | ||
| 846 | |||
| 847 | static const struct v4l2_subdev_core_ops xcsi2rxss_core_ops = { | ||
| 848 | .log_status = xcsi2rxss_log_status, | ||
| 849 | }; | ||
| 850 | |||
| 851 | static const struct v4l2_subdev_video_ops xcsi2rxss_video_ops = { | ||
| 852 | .s_stream = xcsi2rxss_s_stream | ||
| 853 | }; | ||
| 854 | |||
| 855 | static const struct v4l2_subdev_pad_ops xcsi2rxss_pad_ops = { | ||
| 856 | .init_cfg = xcsi2rxss_init_cfg, | ||
| 857 | .get_fmt = xcsi2rxss_get_format, | ||
| 858 | .set_fmt = xcsi2rxss_set_format, | ||
| 859 | .enum_mbus_code = xcsi2rxss_enum_mbus_code, | ||
| 860 | .link_validate = v4l2_subdev_link_validate_default, | ||
| 861 | }; | ||
| 862 | |||
| 863 | static const struct v4l2_subdev_ops xcsi2rxss_ops = { | ||
| 864 | .core = &xcsi2rxss_core_ops, | ||
| 865 | .video = &xcsi2rxss_video_ops, | ||
| 866 | .pad = &xcsi2rxss_pad_ops | ||
| 867 | }; | ||
| 868 | |||
| 869 | static int xcsi2rxss_parse_of(struct xcsi2rxss_state *xcsi2rxss) | ||
| 870 | { | ||
| 871 | struct device *dev = xcsi2rxss->dev; | ||
| 872 | struct device_node *node = dev->of_node; | ||
| 873 | |||
| 874 | struct fwnode_handle *ep; | ||
| 875 | struct v4l2_fwnode_endpoint vep = { | ||
| 876 | .bus_type = V4L2_MBUS_CSI2_DPHY | ||
| 877 | }; | ||
| 878 | bool en_csi_v20, vfb; | ||
| 879 | int ret; | ||
| 880 | |||
| 881 | en_csi_v20 = of_property_read_bool(node, "xlnx,en-csi-v2-0"); | ||
| 882 | if (en_csi_v20) | ||
| 883 | xcsi2rxss->en_vcx = of_property_read_bool(node, "xlnx,en-vcx"); | ||
| 884 | |||
| 885 | xcsi2rxss->enable_active_lanes = | ||
| 886 | of_property_read_bool(node, "xlnx,en-active-lanes"); | ||
| 887 | |||
| 888 | ret = of_property_read_u32(node, "xlnx,csi-pxl-format", | ||
| 889 | &xcsi2rxss->datatype); | ||
| 890 | if (ret < 0) { | ||
| 891 | dev_err(dev, "missing xlnx,csi-pxl-format property\n"); | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | switch (xcsi2rxss->datatype) { | ||
| 896 | case XCSI_DT_YUV4228B: | ||
| 897 | case XCSI_DT_RGB444: | ||
| 898 | case XCSI_DT_RGB555: | ||
| 899 | case XCSI_DT_RGB565: | ||
| 900 | case XCSI_DT_RGB666: | ||
| 901 | case XCSI_DT_RGB888: | ||
| 902 | case XCSI_DT_RAW6: | ||
| 903 | case XCSI_DT_RAW7: | ||
| 904 | case XCSI_DT_RAW8: | ||
| 905 | case XCSI_DT_RAW10: | ||
| 906 | case XCSI_DT_RAW12: | ||
| 907 | case XCSI_DT_RAW14: | ||
| 908 | break; | ||
| 909 | case XCSI_DT_YUV42210B: | ||
| 910 | case XCSI_DT_RAW16: | ||
| 911 | case XCSI_DT_RAW20: | ||
| 912 | if (!en_csi_v20) { | ||
| 913 | ret = -EINVAL; | ||
| 914 | dev_dbg(dev, "enable csi v2 for this pixel format"); | ||
| 915 | } | ||
| 916 | break; | ||
| 917 | default: | ||
| 918 | ret = -EINVAL; | ||
| 919 | } | ||
| 920 | if (ret < 0) { | ||
| 921 | dev_err(dev, "invalid csi-pxl-format property!\n"); | ||
| 922 | return ret; | ||
| 923 | } | ||
| 924 | |||
| 925 | vfb = of_property_read_bool(node, "xlnx,vfb"); | ||
| 926 | if (!vfb) { | ||
| 927 | dev_err(dev, "operation without VFB is not supported\n"); | ||
| 928 | return -EINVAL; | ||
| 929 | } | ||
| 930 | |||
| 931 | ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), | ||
| 932 | XVIP_PAD_SINK, 0, | ||
| 933 | FWNODE_GRAPH_ENDPOINT_NEXT); | ||
| 934 | if (!ep) { | ||
| 935 | dev_err(dev, "no sink port found"); | ||
| 936 | return -EINVAL; | ||
| 937 | } | ||
| 938 | |||
| 939 | ret = v4l2_fwnode_endpoint_parse(ep, &vep); | ||
| 940 | fwnode_handle_put(ep); | ||
| 941 | if (ret) { | ||
| 942 | dev_err(dev, "error parsing sink port"); | ||
| 943 | return ret; | ||
| 944 | } | ||
| 945 | |||
| 946 | dev_dbg(dev, "mipi number lanes = %d\n", | ||
| 947 | vep.bus.mipi_csi2.num_data_lanes); | ||
| 948 | |||
| 949 | xcsi2rxss->max_num_lanes = vep.bus.mipi_csi2.num_data_lanes; | ||
| 950 | |||
| 951 | ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), | ||
| 952 | XVIP_PAD_SOURCE, 0, | ||
| 953 | FWNODE_GRAPH_ENDPOINT_NEXT); | ||
| 954 | if (!ep) { | ||
| 955 | dev_err(dev, "no source port found"); | ||
| 956 | return -EINVAL; | ||
| 957 | } | ||
| 958 | |||
| 959 | fwnode_handle_put(ep); | ||
| 960 | |||
| 961 | dev_dbg(dev, "vcx %s, %u data lanes (%s), data type 0x%02x\n", | ||
| 962 | xcsi2rxss->en_vcx ? "enabled" : "disabled", | ||
| 963 | xcsi2rxss->max_num_lanes, | ||
| 964 | xcsi2rxss->enable_active_lanes ? "dynamic" : "static", | ||
| 965 | xcsi2rxss->datatype); | ||
| 966 | |||
| 967 | return 0; | ||
| 968 | } | ||
| 969 | |||
| 970 | static int xcsi2rxss_probe(struct platform_device *pdev) | ||
| 971 | { | ||
| 972 | struct v4l2_subdev *subdev; | ||
| 973 | struct xcsi2rxss_state *xcsi2rxss; | ||
| 974 | int num_clks = ARRAY_SIZE(xcsi2rxss_clks); | ||
| 975 | struct device *dev = &pdev->dev; | ||
| 976 | int irq, ret; | ||
| 977 | |||
| 978 | xcsi2rxss = devm_kzalloc(dev, sizeof(*xcsi2rxss), GFP_KERNEL); | ||
| 979 | if (!xcsi2rxss) | ||
| 980 | return -ENOMEM; | ||
| 981 | |||
| 982 | xcsi2rxss->dev = dev; | ||
| 983 | |||
| 984 | xcsi2rxss->clks = devm_kmemdup(dev, xcsi2rxss_clks, | ||
| 985 | sizeof(xcsi2rxss_clks), GFP_KERNEL); | ||
| 986 | if (!xcsi2rxss->clks) | ||
| 987 | return -ENOMEM; | ||
| 988 | |||
| 989 | /* Reset GPIO */ | ||
| 990 | xcsi2rxss->rst_gpio = devm_gpiod_get_optional(dev, "video-reset", | ||
| 991 | GPIOD_OUT_HIGH); | ||
| 992 | if (IS_ERR(xcsi2rxss->rst_gpio)) { | ||
| 993 | if (PTR_ERR(xcsi2rxss->rst_gpio) != -EPROBE_DEFER) | ||
| 994 | dev_err(dev, "Video Reset GPIO not setup in DT"); | ||
| 995 | return PTR_ERR(xcsi2rxss->rst_gpio); | ||
| 996 | } | ||
| 997 | |||
| 998 | ret = xcsi2rxss_parse_of(xcsi2rxss); | ||
| 999 | if (ret < 0) | ||
| 1000 | return ret; | ||
| 1001 | |||
| 1002 | xcsi2rxss->iomem = devm_platform_ioremap_resource(pdev, 0); | ||
| 1003 | if (IS_ERR(xcsi2rxss->iomem)) | ||
| 1004 | return PTR_ERR(xcsi2rxss->iomem); | ||
| 1005 | |||
| 1006 | irq = platform_get_irq(pdev, 0); | ||
| 1007 | if (irq < 0) | ||
| 1008 | return irq; | ||
| 1009 | |||
| 1010 | ret = devm_request_threaded_irq(dev, irq, NULL, | ||
| 1011 | xcsi2rxss_irq_handler, IRQF_ONESHOT, | ||
| 1012 | dev_name(dev), xcsi2rxss); | ||
| 1013 | if (ret) { | ||
| 1014 | dev_err(dev, "Err = %d Interrupt handler reg failed!\n", ret); | ||
| 1015 | return ret; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | ret = clk_bulk_get(dev, num_clks, xcsi2rxss->clks); | ||
| 1019 | if (ret) | ||
| 1020 | return ret; | ||
| 1021 | |||
| 1022 | /* TODO: Enable/disable clocks at stream on/off time. */ | ||
| 1023 | ret = clk_bulk_prepare_enable(num_clks, xcsi2rxss->clks); | ||
| 1024 | if (ret) | ||
| 1025 | goto err_clk_put; | ||
| 1026 | |||
| 1027 | mutex_init(&xcsi2rxss->lock); | ||
| 1028 | |||
| 1029 | xcsi2rxss_hard_reset(xcsi2rxss); | ||
| 1030 | xcsi2rxss_soft_reset(xcsi2rxss); | ||
| 1031 | |||
| 1032 | /* Initialize V4L2 subdevice and media entity */ | ||
| 1033 | xcsi2rxss->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | ||
| 1034 | xcsi2rxss->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | ||
| 1035 | |||
| 1036 | /* Initialize the default format */ | ||
| 1037 | xcsi2rxss->default_format.code = | ||
| 1038 | xcsi2rxss_get_nth_mbus(xcsi2rxss->datatype, 0); | ||
| 1039 | xcsi2rxss->default_format.field = V4L2_FIELD_NONE; | ||
| 1040 | xcsi2rxss->default_format.colorspace = V4L2_COLORSPACE_SRGB; | ||
| 1041 | xcsi2rxss->default_format.width = XCSI_DEFAULT_WIDTH; | ||
| 1042 | xcsi2rxss->default_format.height = XCSI_DEFAULT_HEIGHT; | ||
| 1043 | xcsi2rxss->format = xcsi2rxss->default_format; | ||
| 1044 | |||
| 1045 | /* Initialize V4L2 subdevice and media entity */ | ||
| 1046 | subdev = &xcsi2rxss->subdev; | ||
| 1047 | v4l2_subdev_init(subdev, &xcsi2rxss_ops); | ||
| 1048 | subdev->dev = dev; | ||
| 1049 | strscpy(subdev->name, dev_name(dev), sizeof(subdev->name)); | ||
| 1050 | subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 1051 | subdev->entity.ops = &xcsi2rxss_media_ops; | ||
| 1052 | v4l2_set_subdevdata(subdev, xcsi2rxss); | ||
| 1053 | |||
| 1054 | ret = media_entity_pads_init(&subdev->entity, XCSI_MEDIA_PADS, | ||
| 1055 | xcsi2rxss->pads); | ||
| 1056 | if (ret < 0) | ||
| 1057 | goto error; | ||
| 1058 | |||
| 1059 | platform_set_drvdata(pdev, xcsi2rxss); | ||
| 1060 | |||
| 1061 | ret = v4l2_async_register_subdev(subdev); | ||
| 1062 | if (ret < 0) { | ||
| 1063 | dev_err(dev, "failed to register subdev\n"); | ||
| 1064 | goto error; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | return 0; | ||
| 1068 | error: | ||
| 1069 | media_entity_cleanup(&subdev->entity); | ||
| 1070 | mutex_destroy(&xcsi2rxss->lock); | ||
| 1071 | clk_bulk_disable_unprepare(num_clks, xcsi2rxss->clks); | ||
| 1072 | err_clk_put: | ||
| 1073 | clk_bulk_put(num_clks, xcsi2rxss->clks); | ||
| 1074 | return ret; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | static int xcsi2rxss_remove(struct platform_device *pdev) | ||
| 1078 | { | ||
| 1079 | struct xcsi2rxss_state *xcsi2rxss = platform_get_drvdata(pdev); | ||
| 1080 | struct v4l2_subdev *subdev = &xcsi2rxss->subdev; | ||
| 1081 | int num_clks = ARRAY_SIZE(xcsi2rxss_clks); | ||
| 1082 | |||
| 1083 | v4l2_async_unregister_subdev(subdev); | ||
| 1084 | media_entity_cleanup(&subdev->entity); | ||
| 1085 | mutex_destroy(&xcsi2rxss->lock); | ||
| 1086 | clk_bulk_disable_unprepare(num_clks, xcsi2rxss->clks); | ||
| 1087 | clk_bulk_put(num_clks, xcsi2rxss->clks); | ||
| 1088 | |||
| 1089 | return 0; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | static const struct of_device_id xcsi2rxss_of_id_table[] = { | ||
| 1093 | { .compatible = "xlnx,mipi-csi2-rx-subsystem-5.0", }, | ||
| 1094 | { } | ||
| 1095 | }; | ||
| 1096 | MODULE_DEVICE_TABLE(of, xcsi2rxss_of_id_table); | ||
| 1097 | |||
| 1098 | static struct platform_driver xcsi2rxss_driver = { | ||
| 1099 | .driver = { | ||
| 1100 | .name = "xilinx-csi2rxss", | ||
| 1101 | .of_match_table = xcsi2rxss_of_id_table, | ||
| 1102 | }, | ||
| 1103 | .probe = xcsi2rxss_probe, | ||
| 1104 | .remove = xcsi2rxss_remove, | ||
| 1105 | }; | ||
| 1106 | |||
| 1107 | module_platform_driver(xcsi2rxss_driver); | ||
| 1108 | |||
| 1109 | MODULE_AUTHOR("Vishal Sagar <vsagar@xilinx.com>"); | ||
| 1110 | MODULE_DESCRIPTION("Xilinx MIPI CSI-2 Rx Subsystem Driver"); | ||
| 1111 | MODULE_LICENSE("GPL v2"); | ||
| @@ -414,7 +414,7 @@ static int usb_si4713_probe(struct usb_interface *intf, · 413 unmodified lines | |||
| 414 | struct si4713_usb_device *radio; | 414 | struct si4713_usb_device *radio; |
| 415 | struct i2c_adapter *adapter; | 415 | struct i2c_adapter *adapter; |
| 416 | struct v4l2_subdev *sd; | 416 | struct v4l2_subdev *sd; |
| 417 | int retval = -ENOMEM; | 417 | int retval; |
| 418 | 418 | ||
| 419 | dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n", | 419 | dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n", |
| 420 | id->idVendor, id->idProduct); | 420 | id->idVendor, id->idProduct); |
| @@ -530,6 +530,17 @@ config IR_ZX · 529 unmodified lines | |||
| 530 | To compile this driver as a module, choose M here: the | 530 | To compile this driver as a module, choose M here: the |
| 531 | module will be called zx-irdec. | 531 | module will be called zx-irdec. |
| 532 | 532 | ||
| 533 | config IR_TOY | ||
| 534 | tristate "Infrared Toy and IR Droid" | ||
| 535 | depends on RC_CORE | ||
| 536 | depends on USB_ARCH_HAS_HCD | ||
| 537 | help | ||
| 538 | Say Y here if you want to use the Infrared Toy or IR Droid, USB | ||
| 539 | versions. | ||
| 540 | |||
| 541 | To compile this driver as a module, choose M here: the module will be | ||
| 542 | called ir_toy. | ||
| 543 | |||
| 533 | endif #RC_DEVICES | 544 | endif #RC_DEVICES |
| 534 | 545 | ||
| 535 | endif #RC_CORE | 546 | endif #RC_CORE |
| @@ -50,3 +50,4 @@ obj-$(CONFIG_IR_MTK) += mtk-cir.o · 49 unmodified lines | |||
| 50 | obj-$(CONFIG_IR_ZX) += zx-irdec.o | 50 | obj-$(CONFIG_IR_ZX) += zx-irdec.o |
| 51 | obj-$(CONFIG_IR_TANGO) += tango-ir.o | 51 | obj-$(CONFIG_IR_TANGO) += tango-ir.o |
| 52 | obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o | 52 | obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o |
| 53 | obj-$(CONFIG_IR_TOY) += ir_toy.o | ||
| @@ -51,13 +51,6 @@ static inline void fintek_set_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg) · 50 unmodified lines | |||
| 51 | fintek_cr_write(fintek, tmp, reg); | 51 | fintek_cr_write(fintek, tmp, reg); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | /* clear config register bit without changing other bits */ | ||
| 55 | static inline void fintek_clear_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg) | ||
| 56 | { | ||
| 57 | u8 tmp = fintek_cr_read(fintek, reg) & ~val; | ||
| 58 | fintek_cr_write(fintek, tmp, reg); | ||
| 59 | } | ||
| 60 | |||
| 61 | /* enter config mode */ | 54 | /* enter config mode */ |
| 62 | static inline void fintek_config_mode_enable(struct fintek_dev *fintek) | 55 | static inline void fintek_config_mode_enable(struct fintek_dev *fintek) |
| 63 | { | 56 | { |
| @@ -795,7 +795,7 @@ static ssize_t show_associate_remote(struct device *d, · 794 unmodified lines | |||
| 795 | else | 795 | else |
| 796 | strscpy(buf, "closed\n", PAGE_SIZE); | 796 | strscpy(buf, "closed\n", PAGE_SIZE); |
| 797 | 797 | ||
| 798 | dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n"); | 798 | dev_info(d, "Visit https://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n"); |
| 799 | mutex_unlock(&ictx->lock); | 799 | mutex_unlock(&ictx->lock); |
| 800 | return strlen(buf); | 800 | return strlen(buf); |
| 801 | } | 801 | } |
| @@ -0,0 +1,509 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | |||
| 3 | /* | ||
| 4 | * Infrared Toy and IR Droid RC core driver | ||
| 5 | * | ||
| 6 | * Copyright (C) 2020 Sean Young <sean@mess.org> | ||
| 7 | |||
| 8 | * This driver is based on the lirc driver which can be found here: | ||
| 9 | * https://sourceforge.net/p/lirc/git/ci/master/tree/plugins/irtoy.c | ||
| 10 | * Copyright (C) 2011 Peter Kooiman <pkooiman@gmail.com> | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <asm/unaligned.h> | ||
| 14 | #include <linux/completion.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/usb.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/usb/input.h> | ||
| 20 | |||
| 21 | #include <media/rc-core.h> | ||
| 22 | |||
| 23 | static const u8 COMMAND_VERSION[] = { 'v' }; | ||
| 24 | // End transmit and repeat reset command so we exit sump mode | ||
| 25 | static const u8 COMMAND_RESET[] = { 0xff, 0xff, 0, 0, 0, 0, 0 }; | ||
| 26 | static const u8 COMMAND_SMODE_ENTER[] = { 's' }; | ||
| 27 | static const u8 COMMAND_TXSTART[] = { 0x26, 0x24, 0x25, 0x03 }; | ||
| 28 | |||
| 29 | #define REPLY_XMITCOUNT 't' | ||
| 30 | #define REPLY_XMITSUCCESS 'C' | ||
| 31 | #define REPLY_VERSION 'V' | ||
| 32 | #define REPLY_SAMPLEMODEPROTO 'S' | ||
| 33 | |||
| 34 | #define TIMEOUT 500 | ||
| 35 | |||
| 36 | #define LEN_XMITRES 3 | ||
| 37 | #define LEN_VERSION 4 | ||
| 38 | #define LEN_SAMPLEMODEPROTO 3 | ||
| 39 | |||
| 40 | #define MIN_FW_VERSION 20 | ||
| 41 | #define UNIT_NS 21333 | ||
| 42 | #define MAX_TIMEOUT_NS (UNIT_NS * U16_MAX) | ||
| 43 | |||
| 44 | #define MAX_PACKET 64 | ||
| 45 | |||
| 46 | enum state { | ||
| 47 | STATE_IRDATA, | ||
| 48 | STATE_RESET, | ||
| 49 | STATE_COMMAND, | ||
| 50 | STATE_TX, | ||
| 51 | }; | ||
| 52 | |||
| 53 | struct irtoy { | ||
| 54 | struct device *dev; | ||
| 55 | struct usb_device *usbdev; | ||
| 56 | |||
| 57 | struct rc_dev *rc; | ||
| 58 | struct urb *urb_in, *urb_out; | ||
| 59 | |||
| 60 | u8 *in; | ||
| 61 | u8 *out; | ||
| 62 | struct completion command_done; | ||
| 63 | |||
| 64 | bool pulse; | ||
| 65 | enum state state; | ||
| 66 | |||
| 67 | void *tx_buf; | ||
| 68 | uint tx_len; | ||
| 69 | |||
| 70 | uint emitted; | ||
| 71 | uint hw_version; | ||
| 72 | uint sw_version; | ||
| 73 | uint proto_version; | ||
| 74 | |||
| 75 | char phys[64]; | ||
| 76 | }; | ||
| 77 | |||
| 78 | static void irtoy_response(struct irtoy *irtoy, u32 len) | ||
| 79 | { | ||
| 80 | switch (irtoy->state) { | ||
| 81 | case STATE_COMMAND: | ||
| 82 | if (len == LEN_VERSION && irtoy->in[0] == REPLY_VERSION) { | ||
| 83 | uint version; | ||
| 84 | |||
| 85 | irtoy->in[LEN_VERSION] = 0; | ||
| 86 | |||
| 87 | if (kstrtouint(irtoy->in + 1, 10, &version)) { | ||
| 88 | dev_err(irtoy->dev, "invalid version %*phN. Please make sure you are using firmware v20 or higher", | ||
| 89 | LEN_VERSION, irtoy->in); | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | |||
| 93 | dev_dbg(irtoy->dev, "version %s\n", irtoy->in); | ||
| 94 | |||
| 95 | irtoy->hw_version = version / 100; | ||
| 96 | irtoy->sw_version = version % 100; | ||
| 97 | |||
| 98 | irtoy->state = STATE_IRDATA; | ||
| 99 | complete(&irtoy->command_done); | ||
| 100 | } else if (len == LEN_SAMPLEMODEPROTO && | ||
| 101 | irtoy->in[0] == REPLY_SAMPLEMODEPROTO) { | ||
| 102 | uint version; | ||
| 103 | |||
| 104 | irtoy->in[LEN_SAMPLEMODEPROTO] = 0; | ||
| 105 | |||
| 106 | if (kstrtouint(irtoy->in + 1, 10, &version)) { | ||
| 107 | dev_err(irtoy->dev, "invalid sample mode response %*phN", | ||
| 108 | LEN_SAMPLEMODEPROTO, irtoy->in); | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | |||
| 112 | dev_dbg(irtoy->dev, "protocol %s\n", irtoy->in); | ||
| 113 | |||
| 114 | irtoy->proto_version = version; | ||
| 115 | |||
| 116 | irtoy->state = STATE_IRDATA; | ||
| 117 | complete(&irtoy->command_done); | ||
| 118 | } else { | ||
| 119 | dev_err(irtoy->dev, "unexpected response to command: %*phN\n", | ||
| 120 | len, irtoy->in); | ||
| 121 | } | ||
| 122 | break; | ||
| 123 | case STATE_IRDATA: { | ||
| 124 | struct ir_raw_event rawir = { .pulse = irtoy->pulse }; | ||
| 125 | __be16 *in = (__be16 *)irtoy->in; | ||
| 126 | int i; | ||
| 127 | |||
| 128 | for (i = 0; i < len / sizeof(__be16); i++) { | ||
| 129 | u16 v = be16_to_cpu(in[i]); | ||
| 130 | |||
| 131 | if (v == 0xffff) { | ||
| 132 | rawir.pulse = false; | ||
| 133 | } else { | ||
| 134 | rawir.duration = v * UNIT_NS; | ||
| 135 | ir_raw_event_store_with_timeout(irtoy->rc, | ||
| 136 | &rawir); | ||
| 137 | } | ||
| 138 | |||
| 139 | rawir.pulse = !rawir.pulse; | ||
| 140 | } | ||
| 141 | |||
| 142 | irtoy->pulse = rawir.pulse; | ||
| 143 | |||
| 144 | ir_raw_event_handle(irtoy->rc); | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | case STATE_TX: | ||
| 148 | if (irtoy->tx_len == 0) { | ||
| 149 | if (len == LEN_XMITRES && | ||
| 150 | irtoy->in[0] == REPLY_XMITCOUNT) { | ||
| 151 | u16 emitted = get_unaligned_be16(irtoy->in + 1); | ||
| 152 | |||
| 153 | dev_dbg(irtoy->dev, "emitted:%u\n", emitted); | ||
| 154 | |||
| 155 | irtoy->emitted = emitted; | ||
| 156 | } else if (len == 1 && | ||
| 157 | irtoy->in[0] == REPLY_XMITSUCCESS) { | ||
| 158 | irtoy->state = STATE_IRDATA; | ||
| 159 | complete(&irtoy->command_done); | ||
| 160 | } | ||
| 161 | } else { | ||
| 162 | // send next part of tx buffer | ||
| 163 | uint space = irtoy->in[0]; | ||
| 164 | uint buf_len; | ||
| 165 | int err; | ||
| 166 | |||
| 167 | if (len != 1 || space > MAX_PACKET || space == 0) { | ||
| 168 | dev_err(irtoy->dev, "packet length expected: %*phN\n", | ||
| 169 | len, irtoy->in); | ||
| 170 | irtoy->state = STATE_IRDATA; | ||
| 171 | complete(&irtoy->command_done); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | buf_len = min(space, irtoy->tx_len); | ||
| 176 | |||
| 177 | dev_dbg(irtoy->dev, "remaining:%u sending:%u\n", | ||
| 178 | irtoy->tx_len, buf_len); | ||
| 179 | |||
| 180 | memcpy(irtoy->out, irtoy->tx_buf, buf_len); | ||
| 181 | irtoy->urb_out->transfer_buffer_length = buf_len; | ||
| 182 | err = usb_submit_urb(irtoy->urb_out, GFP_ATOMIC); | ||
| 183 | if (err != 0) { | ||
| 184 | dev_err(irtoy->dev, "fail to submit tx buf urb: %d\n", | ||
| 185 | err); | ||
| 186 | irtoy->state = STATE_IRDATA; | ||
| 187 | complete(&irtoy->command_done); | ||
| 188 | break; | ||
| 189 | } | ||
| 190 | |||
| 191 | irtoy->tx_buf += buf_len; | ||
| 192 | irtoy->tx_len -= buf_len; | ||
| 193 | } | ||
| 194 | break; | ||
| 195 | case STATE_RESET: | ||
| 196 | dev_err(irtoy->dev, "unexpected response to reset: %*phN\n", | ||
| 197 | len, irtoy->in); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | static void irtoy_out_callback(struct urb *urb) | ||
| 202 | { | ||
| 203 | struct irtoy *irtoy = urb->context; | ||
| 204 | |||
| 205 | if (urb->status == 0) { | ||
| 206 | if (irtoy->state == STATE_RESET) | ||
| 207 | complete(&irtoy->command_done); | ||
| 208 | } else { | ||
| 209 | dev_warn(irtoy->dev, "out urb status: %d\n", urb->status); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | static void irtoy_in_callback(struct urb *urb) | ||
| 214 | { | ||
| 215 | struct irtoy *irtoy = urb->context; | ||
| 216 | int ret; | ||
| 217 | |||
| 218 | if (urb->status == 0) | ||
| 219 | irtoy_response(irtoy, urb->actual_length); | ||
| 220 | else | ||
| 221 | dev_dbg(irtoy->dev, "in urb status: %d\n", urb->status); | ||
| 222 | |||
| 223 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 224 | if (ret && ret != -ENODEV) | ||
| 225 | dev_warn(irtoy->dev, "failed to resubmit urb: %d\n", ret); | ||
| 226 | } | ||
| 227 | |||
| 228 | static int irtoy_command(struct irtoy *irtoy, const u8 *cmd, int cmd_len, | ||
| 229 | enum state state) | ||
| 230 | { | ||
| 231 | int err; | ||
| 232 | |||
| 233 | init_completion(&irtoy->command_done); | ||
| 234 | |||
| 235 | irtoy->state = state; | ||
| 236 | |||
| 237 | memcpy(irtoy->out, cmd, cmd_len); | ||
| 238 | irtoy->urb_out->transfer_buffer_length = cmd_len; | ||
| 239 | |||
| 240 | err = usb_submit_urb(irtoy->urb_out, GFP_KERNEL); | ||
| 241 | if (err != 0) | ||
| 242 | return err; | ||
| 243 | |||
| 244 | if (!wait_for_completion_timeout(&irtoy->command_done, | ||
| 245 | msecs_to_jiffies(TIMEOUT))) { | ||
| 246 | usb_kill_urb(irtoy->urb_out); | ||
| 247 | return -ETIMEDOUT; | ||
| 248 | } | ||
| 249 | |||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int irtoy_setup(struct irtoy *irtoy) | ||
| 254 | { | ||
| 255 | int err; | ||
| 256 | |||
| 257 | err = irtoy_command(irtoy, COMMAND_RESET, sizeof(COMMAND_RESET), | ||
| 258 | STATE_RESET); | ||
| 259 | if (err != 0) { | ||
| 260 | dev_err(irtoy->dev, "could not write reset command: %d\n", | ||
| 261 | err); | ||
| 262 | return err; | ||
| 263 | } | ||
| 264 | |||
| 265 | usleep_range(50, 50); | ||
| 266 | |||
| 267 | // get version | ||
| 268 | err = irtoy_command(irtoy, COMMAND_VERSION, sizeof(COMMAND_VERSION), | ||
| 269 | STATE_COMMAND); | ||
| 270 | if (err) { | ||
| 271 | dev_err(irtoy->dev, "could not write version command: %d\n", | ||
| 272 | err); | ||
| 273 | return err; | ||
| 274 | } | ||
| 275 | |||
| 276 | // enter sample mode | ||
| 277 | err = irtoy_command(irtoy, COMMAND_SMODE_ENTER, | ||
| 278 | sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND); | ||
| 279 | if (err) | ||
| 280 | dev_err(irtoy->dev, "could not write sample command: %d\n", | ||
| 281 | err); | ||
| 282 | |||
| 283 | return err; | ||
| 284 | } | ||
| 285 | |||
| 286 | /* | ||
| 287 | * When sending IR, it is imperative that we send the IR data as quickly | ||
| 288 | * as possible to the device, so it does not run out of IR data and | ||
| 289 | * introduce gaps. Allocate the buffer here, and then feed the data from | ||
| 290 | * the urb callback handler. | ||
| 291 | */ | ||
| 292 | static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) | ||
| 293 | { | ||
| 294 | struct irtoy *irtoy = rc->priv; | ||
| 295 | unsigned int i, size; | ||
| 296 | __be16 *buf; | ||
| 297 | int err; | ||
| 298 | |||
| 299 | size = sizeof(u16) * (count + 1); | ||
| 300 | buf = kmalloc(size, GFP_KERNEL); | ||
| 301 | if (!buf) | ||
| 302 | return -ENOMEM; | ||
| 303 | |||
| 304 | for (i = 0; i < count; i++) { | ||
| 305 | u16 v = DIV_ROUND_CLOSEST(US_TO_NS(txbuf[i]), UNIT_NS); | ||
| 306 | |||
| 307 | if (!v) | ||
| 308 | v = 1; | ||
| 309 | buf[i] = cpu_to_be16(v); | ||
| 310 | } | ||
| 311 | |||
| 312 | buf[count] = cpu_to_be16(0xffff); | ||
| 313 | |||
| 314 | irtoy->tx_buf = buf; | ||
| 315 | irtoy->tx_len = size; | ||
| 316 | irtoy->emitted = 0; | ||
| 317 | |||
| 318 | err = irtoy_command(irtoy, COMMAND_TXSTART, sizeof(COMMAND_TXSTART), | ||
| 319 | STATE_TX); | ||
| 320 | kfree(buf); | ||
| 321 | |||
| 322 | if (err) { | ||
| 323 | dev_err(irtoy->dev, "failed to send tx start command: %d\n", | ||
| 324 | err); | ||
| 325 | // not sure what state the device is in, reset it | ||
| 326 | irtoy_setup(irtoy); | ||
| 327 | return err; | ||
| 328 | } | ||
| 329 | |||
| 330 | if (size != irtoy->emitted) { | ||
| 331 | dev_err(irtoy->dev, "expected %u emitted, got %u\n", size, | ||
| 332 | irtoy->emitted); | ||
| 333 | // not sure what state the device is in, reset it | ||
| 334 | irtoy_setup(irtoy); | ||
| 335 | return -EINVAL; | ||
| 336 | } | ||
| 337 | |||
| 338 | return count; | ||
| 339 | } | ||
| 340 | |||
| 341 | static int irtoy_probe(struct usb_interface *intf, | ||
| 342 | const struct usb_device_id *id) | ||
| 343 | { | ||
| 344 | struct usb_host_interface *idesc = intf->cur_altsetting; | ||
| 345 | struct usb_device *usbdev = interface_to_usbdev(intf); | ||
| 346 | struct usb_endpoint_descriptor *ep_in = NULL; | ||
| 347 | struct usb_endpoint_descriptor *ep_out = NULL; | ||
| 348 | struct usb_endpoint_descriptor *ep = NULL; | ||
| 349 | struct irtoy *irtoy; | ||
| 350 | struct rc_dev *rc; | ||
| 351 | struct urb *urb; | ||
| 352 | int i, pipe, err = -ENOMEM; | ||
| 353 | |||
| 354 | for (i = 0; i < idesc->desc.bNumEndpoints; i++) { | ||
| 355 | ep = &idesc->endpoint[i].desc; | ||
| 356 | |||
| 357 | if (!ep_in && usb_endpoint_is_bulk_in(ep) && | ||
| 358 | usb_endpoint_maxp(ep) == MAX_PACKET) | ||
| 359 | ep_in = ep; | ||
| 360 | |||
| 361 | if (!ep_out && usb_endpoint_is_bulk_out(ep) && | ||
| 362 | usb_endpoint_maxp(ep) == MAX_PACKET) | ||
| 363 | ep_out = ep; | ||
| 364 | } | ||
| 365 | |||
| 366 | if (!ep_in || !ep_out) { | ||
| 367 | dev_err(&intf->dev, "required endpoints not found\n"); | ||
| 368 | return -ENODEV; | ||
| 369 | } | ||
| 370 | |||
| 371 | irtoy = kzalloc(sizeof(*irtoy), GFP_KERNEL); | ||
| 372 | if (!irtoy) | ||
| 373 | return -ENOMEM; | ||
| 374 | |||
| 375 | irtoy->in = kmalloc(MAX_PACKET, GFP_KERNEL); | ||
| 376 | if (!irtoy->in) | ||
| 377 | goto free_irtoy; | ||
| 378 | |||
| 379 | irtoy->out = kmalloc(MAX_PACKET, GFP_KERNEL); | ||
| 380 | if (!irtoy->out) | ||
| 381 | goto free_irtoy; | ||
| 382 | |||
| 383 | rc = rc_allocate_device(RC_DRIVER_IR_RAW); | ||
| 384 | if (!rc) | ||
| 385 | goto free_irtoy; | ||
| 386 | |||
| 387 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 388 | if (!urb) | ||
| 389 | goto free_rcdev; | ||
| 390 | |||
| 391 | pipe = usb_rcvbulkpipe(usbdev, ep_in->bEndpointAddress); | ||
| 392 | usb_fill_bulk_urb(urb, usbdev, pipe, irtoy->in, MAX_PACKET, | ||
| 393 | irtoy_in_callback, irtoy); | ||
| 394 | irtoy->urb_in = urb; | ||
| 395 | |||
| 396 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 397 | if (!urb) | ||
| 398 | goto free_rcdev; | ||
| 399 | |||
| 400 | pipe = usb_sndbulkpipe(usbdev, ep_out->bEndpointAddress); | ||
| 401 | usb_fill_bulk_urb(urb, usbdev, pipe, irtoy->out, MAX_PACKET, | ||
| 402 | irtoy_out_callback, irtoy); | ||
| 403 | |||
| 404 | irtoy->dev = &intf->dev; | ||
| 405 | irtoy->usbdev = usbdev; | ||
| 406 | irtoy->rc = rc; | ||
| 407 | irtoy->urb_out = urb; | ||
| 408 | irtoy->pulse = true; | ||
| 409 | |||
| 410 | err = usb_submit_urb(irtoy->urb_in, GFP_KERNEL); | ||
| 411 | if (err != 0) { | ||
| 412 | dev_err(irtoy->dev, "fail to submit in urb: %d\n", err); | ||
| 413 | return err; | ||
| 414 | } | ||
| 415 | |||
| 416 | err = irtoy_setup(irtoy); | ||
| 417 | if (err) | ||
| 418 | goto free_rcdev; | ||
| 419 | |||
| 420 | dev_info(irtoy->dev, "version: hardware %u, firmware %u, protocol %u", | ||
| 421 | irtoy->hw_version, irtoy->sw_version, irtoy->proto_version); | ||
| 422 | |||
| 423 | if (irtoy->sw_version < MIN_FW_VERSION) { | ||
| 424 | dev_err(irtoy->dev, "need firmware V%02u or higher", | ||
| 425 | MIN_FW_VERSION); | ||
| 426 | err = -ENODEV; | ||
| 427 | goto free_rcdev; | ||
| 428 | } | ||
| 429 | |||
| 430 | usb_make_path(usbdev, irtoy->phys, sizeof(irtoy->phys)); | ||
| 431 | |||
| 432 | rc->device_name = "Infrared Toy"; | ||
| 433 | rc->driver_name = KBUILD_MODNAME; | ||
| 434 | rc->input_phys = irtoy->phys; | ||
| 435 | usb_to_input_id(usbdev, &rc->input_id); | ||
| 436 | rc->dev.parent = &intf->dev; | ||
| 437 | rc->priv = irtoy; | ||
| 438 | rc->tx_ir = irtoy_tx; | ||
| 439 | rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; | ||
| 440 | rc->map_name = RC_MAP_RC6_MCE; | ||
| 441 | rc->rx_resolution = UNIT_NS; | ||
| 442 | rc->timeout = IR_DEFAULT_TIMEOUT; | ||
| 443 | |||
| 444 | /* | ||
| 445 | * end of transmission is detected by absence of a usb packet | ||
| 446 | * with more pulse/spaces. However, each usb packet sent can | ||
| 447 | * contain 32 pulse/spaces, which can be quite lengthy, so there | ||
| 448 | * can be a delay between usb packets. For example with nec there is a | ||
| 449 | * 17ms gap between packets. | ||
| 450 | * | ||
| 451 | * So, make timeout a largish minimum which works with most protocols. | ||
| 452 | */ | ||
| 453 | rc->min_timeout = MS_TO_NS(40); | ||
| 454 | rc->max_timeout = MAX_TIMEOUT_NS; | ||
| 455 | |||
| 456 | err = rc_register_device(rc); | ||
| 457 | if (err) | ||
| 458 | goto free_rcdev; | ||
| 459 | |||
| 460 | usb_set_intfdata(intf, irtoy); | ||
| 461 | |||
| 462 | return 0; | ||
| 463 | |||
| 464 | free_rcdev: | ||
| 465 | usb_kill_urb(irtoy->urb_out); | ||
| 466 | usb_free_urb(irtoy->urb_out); | ||
| 467 | usb_kill_urb(irtoy->urb_in); | ||
| 468 | usb_free_urb(irtoy->urb_in); | ||
| 469 | rc_free_device(rc); | ||
| 470 | free_irtoy: | ||
| 471 | kfree(irtoy->in); | ||
| 472 | kfree(irtoy->out); | ||
| 473 | kfree(irtoy); | ||
| 474 | return err; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void irtoy_disconnect(struct usb_interface *intf) | ||
| 478 | { | ||
| 479 | struct irtoy *ir = usb_get_intfdata(intf); | ||
| 480 | |||
| 481 | rc_unregister_device(ir->rc); | ||
| 482 | usb_set_intfdata(intf, NULL); | ||
| 483 | usb_kill_urb(ir->urb_out); | ||
| 484 | usb_free_urb(ir->urb_out); | ||
| 485 | usb_kill_urb(ir->urb_in); | ||
| 486 | usb_free_urb(ir->urb_in); | ||
| 487 | kfree(ir->in); | ||
| 488 | kfree(ir->out); | ||
| 489 | kfree(ir); | ||
| 490 | } | ||
| 491 | |||
| 492 | static const struct usb_device_id irtoy_table[] = { | ||
| 493 | { USB_DEVICE_INTERFACE_CLASS(0x04d8, 0xfd08, USB_CLASS_CDC_DATA) }, | ||
| 494 | { } | ||
| 495 | }; | ||
| 496 | |||
| 497 | static struct usb_driver irtoy_driver = { | ||
| 498 | .name = KBUILD_MODNAME, | ||
| 499 | .probe = irtoy_probe, | ||
| 500 | .disconnect = irtoy_disconnect, | ||
| 501 | .id_table = irtoy_table, | ||
| 502 | }; | ||
| 503 | |||
| 504 | module_usb_driver(irtoy_driver); | ||
| 505 | |||
| 506 | MODULE_AUTHOR("Sean Young <sean@mess.org>"); | ||
| 507 | MODULE_DESCRIPTION("Infrared Toy and IR Droid driver"); | ||
| 508 | MODULE_LICENSE("GPL"); | ||
| 509 | MODULE_DEVICE_TABLE(usb, irtoy_table); | ||
| @@ -74,13 +74,6 @@ static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) · 73 unmodified lines | |||
| 74 | nvt_cr_write(nvt, tmp, reg); | 74 | nvt_cr_write(nvt, tmp, reg); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /* clear config register bit without changing other bits */ | ||
| 78 | static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) | ||
| 79 | { | ||
| 80 | u8 tmp = nvt_cr_read(nvt, reg) & ~val; | ||
| 81 | nvt_cr_write(nvt, tmp, reg); | ||
| 82 | } | ||
| 83 | |||
| 84 | /* enter extended function mode */ | 77 | /* enter extended function mode */ |
| 85 | static inline int nvt_efm_enable(struct nvt_dev *nvt) | 78 | static inline int nvt_efm_enable(struct nvt_dev *nvt) |
| 86 | { | 79 | { |
| @@ -631,30 +624,6 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) · 544 unmodified lines | |||
| 631 | return carrier; | 624 | return carrier; |
| 632 | } | 625 | } |
| 633 | #endif | 626 | #endif |
| 634 | /* | ||
| 635 | * set carrier frequency | ||
| 636 | * | ||
| 637 | * set carrier on 2 registers: CP & CC | ||
| 638 | * always set CP as 0x81 | ||
| 639 | * set CC by SPEC, CC = 3MHz/carrier - 1 | ||
| 640 | */ | ||
| 641 | static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) | ||
| 642 | { | ||
| 643 | struct nvt_dev *nvt = dev->priv; | ||
| 644 | u16 val; | ||
| 645 | |||
| 646 | if (carrier == 0) | ||
| 647 | return -EINVAL; | ||
| 648 | |||
| 649 | nvt_cir_reg_write(nvt, 1, CIR_CP); | ||
| 650 | val = 3000000 / (carrier) - 1; | ||
| 651 | nvt_cir_reg_write(nvt, val & 0xff, CIR_CC); | ||
| 652 | |||
| 653 | nvt_dbg("cp: 0x%x cc: 0x%x\n", | ||
| 654 | nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC)); | ||
| 655 | |||
| 656 | return 0; | ||
| 657 | } | ||
| 658 | 627 | ||
| 659 | static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev, | 628 | static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev, |
| 660 | struct rc_scancode_filter *sc_filter) | 629 | struct rc_scancode_filter *sc_filter) |
| @@ -1022,7 +991,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) · 361 unmodified lines | |||
| 1022 | rdev->encode_wakeup = true; | 991 | rdev->encode_wakeup = true; |
| 1023 | rdev->open = nvt_open; | 992 | rdev->open = nvt_open; |
| 1024 | rdev->close = nvt_close; | 993 | rdev->close = nvt_close; |
| 1025 | rdev->s_tx_carrier = nvt_set_tx_carrier; | ||
| 1026 | rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter; | 994 | rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter; |
| 1027 | rdev->device_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; | 995 | rdev->device_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; |
| 1028 | rdev->input_phys = "nuvoton/cir0"; | 996 | rdev->input_phys = "nuvoton/cir0"; |
| @@ -2052,7 +2052,7 @@ static int __init rc_core_init(void) · 2051 unmodified lines | |||
| 2052 | if (rc) { | 2052 | if (rc) { |
| 2053 | pr_err("rc_core: unable to init lirc\n"); | 2053 | pr_err("rc_core: unable to init lirc\n"); |
| 2054 | class_unregister(&rc_class); | 2054 | class_unregister(&rc_class); |
| 2055 | return 0; | 2055 | return rc; |
| 2056 | } | 2056 | } |
| 2057 | 2057 | ||
| 2058 | led_trigger_register_simple("rc-feedback", &led_feedback); | 2058 | led_trigger_register_simple("rc-feedback", &led_feedback); |
| @@ -1442,7 +1442,7 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) · 1441 unmodified lines | |||
| 1442 | .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, | 1442 | .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, |
| 1443 | }; | 1443 | }; |
| 1444 | 1444 | ||
| 1445 | if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && | 1445 | if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && |
| 1446 | vb2_is_streaming(vb->vb2_queue) && | 1446 | vb2_is_streaming(vb->vb2_queue) && |
| 1447 | v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { | 1447 | v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { |
| 1448 | unsigned int i; | 1448 | unsigned int i; |
| @@ -1479,7 +1479,7 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) · 30 unmodified lines | |||
| 1479 | * in the compressed stream | 1479 | * in the compressed stream |
| 1480 | */ | 1480 | */ |
| 1481 | if (ctx->is_stateless || ctx->is_enc || | 1481 | if (ctx->is_stateless || ctx->is_enc || |
| 1482 | !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { | 1482 | V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { |
| 1483 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | 1483 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
| 1484 | return; | 1484 | return; |
| 1485 | } | 1485 | } |
| @@ -1574,7 +1574,7 @@ static int vicodec_start_streaming(struct vb2_queue *q, · 88 unmodified lines | |||
| 1574 | state->gop_cnt = 0; | 1574 | state->gop_cnt = 0; |
| 1575 | 1575 | ||
| 1576 | if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || | 1576 | if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || |
| 1577 | (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) | 1577 | (V4L2_TYPE_IS_CAPTURE(q->type) && ctx->is_enc)) |
| 1578 | return 0; | 1578 | return 0; |
| 1579 | 1579 | ||
| 1580 | if (info->id == V4L2_PIX_FMT_FWHT || | 1580 | if (info->id == V4L2_PIX_FMT_FWHT || |
| @@ -2,6 +2,8 @@ · 1 unmodified line | |||
| 2 | config VIDEO_VIMC | 2 | config VIDEO_VIMC |
| 3 | tristate "Virtual Media Controller Driver (VIMC)" | 3 | tristate "Virtual Media Controller Driver (VIMC)" |
| 4 | depends on VIDEO_DEV && VIDEO_V4L2 | 4 | depends on VIDEO_DEV && VIDEO_V4L2 |
| 5 | select FONT_SUPPORT | ||
| 6 | select FONT_8x16 | ||
| 5 | select MEDIA_CONTROLLER | 7 | select MEDIA_CONTROLLER |
| 6 | select VIDEO_V4L2_SUBDEV_API | 8 | select VIDEO_V4L2_SUBDEV_API |
| 7 | select VIDEOBUF2_VMALLOC | 9 | select VIDEOBUF2_VMALLOC |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #define VIMC_CID_VIMC_CLASS (0x00f00000 | 1) | 20 | #define VIMC_CID_VIMC_CLASS (0x00f00000 | 1) |
| 21 | #define VIMC_CID_TEST_PATTERN (VIMC_CID_VIMC_BASE + 0) | 21 | #define VIMC_CID_TEST_PATTERN (VIMC_CID_VIMC_BASE + 0) |
| 22 | #define VIMC_CID_MEAN_WIN_SIZE (VIMC_CID_VIMC_BASE + 1) | 22 | #define VIMC_CID_MEAN_WIN_SIZE (VIMC_CID_VIMC_BASE + 1) |
| 23 | #define VIMC_CID_OSD_TEXT_MODE (VIMC_CID_VIMC_BASE + 2) | ||
| 23 | 24 | ||
| 24 | #define VIMC_FRAME_MAX_WIDTH 4096 | 25 | #define VIMC_FRAME_MAX_WIDTH 4096 |
| 25 | #define VIMC_FRAME_MAX_HEIGHT 2160 | 26 | #define VIMC_FRAME_MAX_HEIGHT 2160 |
| @@ -5,10 +5,12 @@ · 4 unmodified lines | |||
| 5 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | 5 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/font.h> | ||
| 8 | #include <linux/init.h> | 9 | #include <linux/init.h> |
| 9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 10 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
| 11 | #include <media/media-device.h> | 12 | #include <media/media-device.h> |
| 13 | #include <media/tpg/v4l2-tpg.h> | ||
| 12 | #include <media/v4l2-device.h> | 14 | #include <media/v4l2-device.h> |
| 13 | 15 | ||
| 14 | #include "vimc-common.h" | 16 | #include "vimc-common.h" |
| @@ -263,11 +265,19 @@ err_v4l2_unregister: · 248 unmodified lines | |||
| 263 | 265 | ||
| 264 | static int vimc_probe(struct platform_device *pdev) | 266 | static int vimc_probe(struct platform_device *pdev) |
| 265 | { | 267 | { |
| 268 | const struct font_desc *font = find_font("VGA8x16"); | ||
| 266 | struct vimc_device *vimc; | 269 | struct vimc_device *vimc; |
| 267 | int ret; | 270 | int ret; |
| 268 | 271 | ||
| 269 | dev_dbg(&pdev->dev, "probe"); | 272 | dev_dbg(&pdev->dev, "probe"); |
| 270 | 273 | ||
| 274 | if (!font) { | ||
| 275 | dev_err(&pdev->dev, "could not find font\n"); | ||
| 276 | return -ENODEV; | ||
| 277 | } | ||
| 278 | |||
| 279 | tpg_set_font(font->data); | ||
| 280 | |||
| 271 | vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); | 281 | vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); |
| 272 | if (!vimc) | 282 | if (!vimc) |
| 273 | return -ENOMEM; | 283 | return -ENOMEM; |
| @@ -14,11 +14,19 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | #include "vimc-common.h" | 15 | #include "vimc-common.h" |
| 16 | 16 | ||
| 17 | enum vimc_sen_osd_mode { | ||
| 18 | VIMC_SEN_OSD_SHOW_ALL = 0, | ||
| 19 | VIMC_SEN_OSD_SHOW_COUNTERS = 1, | ||
| 20 | VIMC_SEN_OSD_SHOW_NONE = 2 | ||
| 21 | }; | ||
| 22 | |||
| 17 | struct vimc_sen_device { | 23 | struct vimc_sen_device { |
| 18 | struct vimc_ent_device ved; | 24 | struct vimc_ent_device ved; |
| 19 | struct v4l2_subdev sd; | 25 | struct v4l2_subdev sd; |
| 20 | struct tpg_data tpg; | 26 | struct tpg_data tpg; |
| 21 | u8 *frame; | 27 | u8 *frame; |
| 28 | enum vimc_sen_osd_mode osd_value; | ||
| 29 | u64 start_stream_ts; | ||
| 22 | /* The active format */ | 30 | /* The active format */ |
| 23 | struct v4l2_mbus_framefmt mbus_format; | 31 | struct v4l2_mbus_framefmt mbus_format; |
| 24 | struct v4l2_ctrl_handler hdl; | 32 | struct v4l2_ctrl_handler hdl; |
| @@ -187,8 +195,49 @@ static void *vimc_sen_process_frame(struct vimc_ent_device *ved, · 162 unmodified lines | |||
| 187 | { | 195 | { |
| 188 | struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, | 196 | struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, |
| 189 | ved); | 197 | ved); |
| 198 | const unsigned int line_height = 16; | ||
| 199 | u8 *basep[TPG_MAX_PLANES][2]; | ||
| 200 | unsigned int line = 1; | ||
| 201 | char str[100]; | ||
| 190 | 202 | ||
| 191 | tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); | 203 | tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); |
| 204 | tpg_calc_text_basep(&vsen->tpg, basep, 0, vsen->frame); | ||
| 205 | switch (vsen->osd_value) { | ||
| 206 | case VIMC_SEN_OSD_SHOW_ALL: { | ||
| 207 | const char *order = tpg_g_color_order(&vsen->tpg); | ||
| 208 | |||
| 209 | tpg_gen_text(&vsen->tpg, basep, line++ * line_height, | ||
| 210 | 16, order); | ||
| 211 | snprintf(str, sizeof(str), | ||
| 212 | "brightness %3d, contrast %3d, saturation %3d, hue %d ", | ||
| 213 | vsen->tpg.brightness, | ||
| 214 | vsen->tpg.contrast, | ||
| 215 | vsen->tpg.saturation, | ||
| 216 | vsen->tpg.hue); | ||
| 217 | tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); | ||
| 218 | snprintf(str, sizeof(str), "sensor size: %dx%d", | ||
| 219 | vsen->mbus_format.width, | ||
| 220 | vsen->mbus_format.height); | ||
| 221 | tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); | ||
| 222 | fallthrough; | ||
| 223 | } | ||
| 224 | case VIMC_SEN_OSD_SHOW_COUNTERS: { | ||
| 225 | unsigned int ms; | ||
| 226 | |||
| 227 | ms = div_u64(ktime_get_ns() - vsen->start_stream_ts, 1000000); | ||
| 228 | snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d", | ||
| 229 | (ms / (60 * 60 * 1000)) % 24, | ||
| 230 | (ms / (60 * 1000)) % 60, | ||
| 231 | (ms / 1000) % 60, | ||
| 232 | ms % 1000); | ||
| 233 | tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | case VIMC_SEN_OSD_SHOW_NONE: | ||
| 237 | default: | ||
| 238 | break; | ||
| 239 | } | ||
| 240 | |||
| 192 | return vsen->frame; | 241 | return vsen->frame; |
| 193 | } | 242 | } |
| 194 | 243 | ||
| @@ -201,6 +250,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) · 6 unmodified lines | |||
| 201 | const struct vimc_pix_map *vpix; | 250 | const struct vimc_pix_map *vpix; |
| 202 | unsigned int frame_size; | 251 | unsigned int frame_size; |
| 203 | 252 | ||
| 253 | vsen->start_stream_ts = ktime_get_ns(); | ||
| 254 | |||
| 204 | /* Calculate the frame size */ | 255 | /* Calculate the frame size */ |
| 205 | vpix = vimc_pix_map_by_code(vsen->mbus_format.code); | 256 | vpix = vimc_pix_map_by_code(vsen->mbus_format.code); |
| 206 | frame_size = vsen->mbus_format.width * vpix->bpp * | 257 | frame_size = vsen->mbus_format.width * vpix->bpp * |
| @@ -269,6 +320,9 @@ static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl) · 62 unmodified lines | |||
| 269 | case V4L2_CID_SATURATION: | 320 | case V4L2_CID_SATURATION: |
| 270 | tpg_s_saturation(&vsen->tpg, ctrl->val); | 321 | tpg_s_saturation(&vsen->tpg, ctrl->val); |
| 271 | break; | 322 | break; |
| 323 | case VIMC_CID_OSD_TEXT_MODE: | ||
| 324 | vsen->osd_value = ctrl->val; | ||
| 325 | break; | ||
| 272 | default: | 326 | default: |
| 273 | return -EINVAL; | 327 | return -EINVAL; |
| 274 | } | 328 | } |
| @@ -307,6 +361,22 @@ static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = { · 32 unmodified lines | |||
| 307 | .qmenu = tpg_pattern_strings, | 361 | .qmenu = tpg_pattern_strings, |
| 308 | }; | 362 | }; |
| 309 | 363 | ||
| 364 | static const char * const vimc_ctrl_osd_mode_strings[] = { | ||
| 365 | "All", | ||
| 366 | "Counters Only", | ||
| 367 | "None", | ||
| 368 | NULL, | ||
| 369 | }; | ||
| 370 | |||
| 371 | static const struct v4l2_ctrl_config vimc_sen_ctrl_osd_mode = { | ||
| 372 | .ops = &vimc_sen_ctrl_ops, | ||
| 373 | .id = VIMC_CID_OSD_TEXT_MODE, | ||
| 374 | .name = "Show Information", | ||
| 375 | .type = V4L2_CTRL_TYPE_MENU, | ||
| 376 | .max = ARRAY_SIZE(vimc_ctrl_osd_mode_strings) - 2, | ||
| 377 | .qmenu = vimc_ctrl_osd_mode_strings, | ||
| 378 | }; | ||
| 379 | |||
| 310 | static struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, | 380 | static struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, |
| 311 | const char *vcfg_name) | 381 | const char *vcfg_name) |
| 312 | { | 382 | { |
| @@ -323,6 +393,7 @@ static struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, · 10 unmodified lines | |||
| 323 | 393 | ||
| 324 | v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL); | 394 | v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL); |
| 325 | v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL); | 395 | v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL); |
| 396 | v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_osd_mode, NULL); | ||
| 326 | v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, | 397 | v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, |
| 327 | V4L2_CID_VFLIP, 0, 1, 1, 0); | 398 | V4L2_CID_VFLIP, 0, 1, 1, 0); |
| 328 | v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, | 399 | v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, |
| @@ -169,6 +169,14 @@ MODULE_PARM_DESC(allocators, " memory allocator selection, default is 0.\n" · 168 unmodified lines | |||
| 169 | "\t\t 0 == vmalloc\n" | 169 | "\t\t 0 == vmalloc\n" |
| 170 | "\t\t 1 == dma-contig"); | 170 | "\t\t 1 == dma-contig"); |
| 171 | 171 | ||
| 172 | static unsigned int cache_hints[VIVID_MAX_DEVS] = { | ||
| 173 | [0 ... (VIVID_MAX_DEVS - 1)] = 0 | ||
| 174 | }; | ||
| 175 | module_param_array(cache_hints, uint, NULL, 0444); | ||
| 176 | MODULE_PARM_DESC(cache_hints, " user-space cache hints, default is 0.\n" | ||
| 177 | "\t\t 0 == forbid\n" | ||
| 178 | "\t\t 1 == allow"); | ||
| 179 | |||
| 172 | static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; | 180 | static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; |
| 173 | 181 | ||
| 174 | const struct v4l2_rect vivid_min_rect = { | 182 | const struct v4l2_rect vivid_min_rect = { |
| @@ -819,6 +827,7 @@ static int vivid_create_queue(struct vivid_dev *dev, · 644 unmodified lines | |||
| 819 | q->lock = &dev->mutex; | 827 | q->lock = &dev->mutex; |
| 820 | q->dev = dev->v4l2_dev.dev; | 828 | q->dev = dev->v4l2_dev.dev; |
| 821 | q->supports_requests = true; | 829 | q->supports_requests = true; |
| 830 | q->allow_cache_hints = (cache_hints[dev->inst] == 1); | ||
| 822 | 831 | ||
| 823 | return vb2_queue_init(q); | 832 | return vb2_queue_init(q); |
| 824 | } | 833 | } |
| @@ -1117,7 +1126,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) · 292 unmodified lines | |||
| 1117 | ret = -ENOMEM; | 1126 | ret = -ENOMEM; |
| 1118 | /* initialize the test pattern generator */ | 1127 | /* initialize the test pattern generator */ |
| 1119 | tpg_init(&dev->tpg, 640, 360); | 1128 | tpg_init(&dev->tpg, 640, 360); |
| 1120 | if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH)) | 1129 | if (tpg_alloc(&dev->tpg, array_size(MAX_WIDTH, MAX_ZOOM))) |
| 1121 | goto free_dev; | 1130 | goto free_dev; |
| 1122 | dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); | 1131 | dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); |
| 1123 | if (!dev->scaled_line) | 1132 | if (!dev->scaled_line) |
| @@ -1127,7 +1136,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) · 3 unmodified lines | |||
| 1127 | goto free_dev; | 1136 | goto free_dev; |
| 1128 | 1137 | ||
| 1129 | /* load the edid */ | 1138 | /* load the edid */ |
| 1130 | dev->edid = vmalloc(256 * 128); | 1139 | dev->edid = vmalloc(array_size(256, 128)); |
| 1131 | if (!dev->edid) | 1140 | if (!dev->edid) |
| 1132 | goto free_dev; | 1141 | goto free_dev; |
| 1133 | 1142 | ||
| @@ -1734,7 +1734,7 @@ static void cx231xx_video_dev_init( · 1733 unmodified lines | |||
| 1734 | int cx231xx_417_register(struct cx231xx *dev) | 1734 | int cx231xx_417_register(struct cx231xx *dev) |
| 1735 | { | 1735 | { |
| 1736 | /* FIXME: Port1 hardcoded here */ | 1736 | /* FIXME: Port1 hardcoded here */ |
| 1737 | int err = -ENODEV; | 1737 | int err; |
| 1738 | struct cx231xx_tsport *tsport = &dev->ts1; | 1738 | struct cx231xx_tsport *tsport = &dev->ts1; |
| 1739 | struct vb2_queue *q; | 1739 | struct vb2_queue *q; |
| 1740 | 1740 | ||
| @@ -778,16 +778,16 @@ static const struct usb_device_id dvbsky_id_table[] = { · 777 unmodified lines | |||
| 778 | &dvbsky_s960_props, "Terratec Cinergy S2 Rev.4", | 778 | &dvbsky_s960_props, "Terratec Cinergy S2 Rev.4", |
| 779 | RC_MAP_DVBSKY) }, | 779 | RC_MAP_DVBSKY) }, |
| 780 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230, | 780 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230, |
| 781 | &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230", | 781 | &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230", |
| 782 | RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, | 782 | RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, |
| 783 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, | 783 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, |
| 784 | &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", | 784 | &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C", |
| 785 | RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, | 785 | RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, |
| 786 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C_LITE, | 786 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C_LITE, |
| 787 | &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C Lite", | 787 | &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C Lite", |
| 788 | NULL) }, | 788 | NULL) }, |
| 789 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, | 789 | { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, |
| 790 | &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C v2", | 790 | &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2", |
| 791 | RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, | 791 | RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, |
| 792 | { } | 792 | { } |
| 793 | }; | 793 | }; |
| @@ -151,6 +151,7 @@ config DVB_USB_CXUSB · 150 unmodified lines | |||
| 151 | config DVB_USB_CXUSB_ANALOG | 151 | config DVB_USB_CXUSB_ANALOG |
| 152 | bool "Analog support for the Conexant USB2.0 hybrid reference design" | 152 | bool "Analog support for the Conexant USB2.0 hybrid reference design" |
| 153 | depends on DVB_USB_CXUSB && VIDEO_V4L2 | 153 | depends on DVB_USB_CXUSB && VIDEO_V4L2 |
| 154 | depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_USB_CXUSB | ||
| 154 | select VIDEO_CX25840 | 155 | select VIDEO_CX25840 |
| 155 | select VIDEOBUF2_VMALLOC | 156 | select VIDEOBUF2_VMALLOC |
| 156 | help | 157 | help |
| @@ -1132,6 +1132,10 @@ static int go7007_usb_probe(struct usb_interface *intf, · 1131 unmodified lines | |||
| 1132 | go->hpi_ops = &go7007_usb_onboard_hpi_ops; | 1132 | go->hpi_ops = &go7007_usb_onboard_hpi_ops; |
| 1133 | go->hpi_context = usb; | 1133 | go->hpi_context = usb; |
| 1134 | 1134 | ||
| 1135 | ep = usb->usbdev->ep_in[4]; | ||
| 1136 | if (!ep) | ||
| 1137 | return -ENODEV; | ||
| 1138 | |||
| 1135 | /* Allocate the URB and buffer for receiving incoming interrupts */ | 1139 | /* Allocate the URB and buffer for receiving incoming interrupts */ |
| 1136 | usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | 1140 | usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); |
| 1137 | if (usb->intr_urb == NULL) | 1141 | if (usb->intr_urb == NULL) |
| @@ -1141,7 +1145,6 @@ static int go7007_usb_probe(struct usb_interface *intf, · 3 unmodified lines | |||
| 1141 | if (usb->intr_urb->transfer_buffer == NULL) | 1145 | if (usb->intr_urb->transfer_buffer == NULL) |
| 1142 | goto allocfail; | 1146 | goto allocfail; |
| 1143 | 1147 | ||
| 1144 | ep = usb->usbdev->ep_in[4]; | ||
| 1145 | if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) | 1148 | if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) |
| 1146 | usb_fill_bulk_urb(usb->intr_urb, usb->usbdev, | 1149 | usb_fill_bulk_urb(usb->intr_urb, usb->usbdev, |
| 1147 | usb_rcvbulkpipe(usb->usbdev, 4), | 1150 | usb_rcvbulkpipe(usb->usbdev, 4), |
| @@ -1263,9 +1266,13 @@ static int go7007_usb_probe(struct usb_interface *intf, · 115 unmodified lines | |||
| 1263 | 1266 | ||
| 1264 | /* Allocate the URBs and buffers for receiving the video stream */ | 1267 | /* Allocate the URBs and buffers for receiving the video stream */ |
| 1265 | if (board->flags & GO7007_USB_EZUSB) { | 1268 | if (board->flags & GO7007_USB_EZUSB) { |
| 1269 | if (!usb->usbdev->ep_in[6]) | ||
| 1270 | goto allocfail; | ||
| 1266 | v_urb_len = 1024; | 1271 | v_urb_len = 1024; |
| 1267 | video_pipe = usb_rcvbulkpipe(usb->usbdev, 6); | 1272 | video_pipe = usb_rcvbulkpipe(usb->usbdev, 6); |
| 1268 | } else { | 1273 | } else { |
| 1274 | if (!usb->usbdev->ep_in[1]) | ||
| 1275 | goto allocfail; | ||
| 1269 | v_urb_len = 512; | 1276 | v_urb_len = 512; |
| 1270 | video_pipe = usb_rcvbulkpipe(usb->usbdev, 1); | 1277 | video_pipe = usb_rcvbulkpipe(usb->usbdev, 1); |
| 1271 | } | 1278 | } |
| @@ -1285,6 +1292,8 @@ static int go7007_usb_probe(struct usb_interface *intf, · 13 unmodified lines | |||
| 1285 | /* Allocate the URBs and buffers for receiving the audio stream */ | 1292 | /* Allocate the URBs and buffers for receiving the audio stream */ |
| 1286 | if ((board->flags & GO7007_USB_EZUSB) && | 1293 | if ((board->flags & GO7007_USB_EZUSB) && |
| 1287 | (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) { | 1294 | (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) { |
| 1295 | if (!usb->usbdev->ep_in[8]) | ||
| 1296 | goto allocfail; | ||
| 1288 | for (i = 0; i < 8; ++i) { | 1297 | for (i = 0; i < 8; ++i) { |
| 1289 | usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); | 1298 | usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); |
| 1290 | if (usb->audio_urbs[i] == NULL) | 1299 | if (usb->audio_urbs[i] == NULL) |
| @@ -925,7 +925,7 @@ static int wxh_to_nearest_mode(struct gspca_dev *gspca_dev, · 924 unmodified lines | |||
| 925 | { | 925 | { |
| 926 | int i; | 926 | int i; |
| 927 | 927 | ||
| 928 | for (i = gspca_dev->cam.nmodes; --i > 0; ) { | 928 | for (i = gspca_dev->cam.nmodes; --i >= 0; ) { |
| 929 | if (width >= gspca_dev->cam.cam_mode[i].width | 929 | if (width >= gspca_dev->cam.cam_mode[i].width |
| 930 | && height >= gspca_dev->cam.cam_mode[i].height | 930 | && height >= gspca_dev->cam.cam_mode[i].height |
| 931 | && pixelformat == gspca_dev->cam.cam_mode[i].pixelformat) | 931 | && pixelformat == gspca_dev->cam.cam_mode[i].pixelformat) |
| @@ -165,7 +165,7 @@ static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) · 164 unmodified lines | |||
| 165 | { | 165 | { |
| 166 | struct sd *sd = (struct sd *)gspca_dev; | 166 | struct sd *sd = (struct sd *)gspca_dev; |
| 167 | int i = 0; | 167 | int i = 0; |
| 168 | int retval = -1; | 168 | int retval; |
| 169 | unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f}; | 169 | unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f}; |
| 170 | 170 | ||
| 171 | gspca_dbg(gspca_dev, D_PROBE, "Running jl2005c_get_firmware_id\n"); | 171 | gspca_dbg(gspca_dev, D_PROBE, "Running jl2005c_get_firmware_id\n"); |
| @@ -14,7 +14,7 @@ · 13 unmodified lines | |||
| 14 | * PS3 Eye camera - brightness, contrast, awb, agc, aec controls | 14 | * PS3 Eye camera - brightness, contrast, awb, agc, aec controls |
| 15 | * added by Max Thrun <bear24rw@gmail.com> | 15 | * added by Max Thrun <bear24rw@gmail.com> |
| 16 | * PS3 Eye camera - FPS range extended by Joseph Howse | 16 | * PS3 Eye camera - FPS range extended by Joseph Howse |
| 17 | * <josephhowse@nummist.com> http://nummist.com | 17 | * <josephhowse@nummist.com> https://nummist.com |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 20 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| @@ -215,7 +215,7 @@ static int sd_config(struct gspca_dev *gspca_dev, · 214 unmodified lines | |||
| 215 | /* this function is called at probe and resume time */ | 215 | /* this function is called at probe and resume time */ |
| 216 | static int sd_init(struct gspca_dev *gspca_dev) | 216 | static int sd_init(struct gspca_dev *gspca_dev) |
| 217 | { | 217 | { |
| 218 | int status = -1; | 218 | int status; |
| 219 | 219 | ||
| 220 | sn9c2028_read1(gspca_dev); | 220 | sn9c2028_read1(gspca_dev); |
| 221 | sn9c2028_read1(gspca_dev); | 221 | sn9c2028_read1(gspca_dev); |
| @@ -50,7 +50,8 @@ static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n) · 49 unmodified lines | |||
| 50 | return n->ops->complete(n); | 50 | return n->ops->complete(n); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) | 53 | static bool match_i2c(struct v4l2_async_notifier *notifier, |
| 54 | struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) | ||
| 54 | { | 55 | { |
| 55 | #if IS_ENABLED(CONFIG_I2C) | 56 | #if IS_ENABLED(CONFIG_I2C) |
| 56 | struct i2c_client *client = i2c_verify_client(sd->dev); | 57 | struct i2c_client *client = i2c_verify_client(sd->dev); |
| @@ -63,18 +64,83 @@ static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) · 6 unmodified lines | |||
| 63 | #endif | 64 | #endif |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | static bool match_devname(struct v4l2_subdev *sd, | 67 | static bool match_devname(struct v4l2_async_notifier *notifier, |
| 67 | struct v4l2_async_subdev *asd) | 68 | struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) |
| 68 | { | 69 | { |
| 69 | return !strcmp(asd->match.device_name, dev_name(sd->dev)); | 70 | return !strcmp(asd->match.device_name, dev_name(sd->dev)); |
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) | 73 | static bool match_fwnode(struct v4l2_async_notifier *notifier, |
| 74 | struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) | ||
| 73 | { | 75 | { |
| 74 | return sd->fwnode == asd->match.fwnode; | 76 | struct fwnode_handle *other_fwnode; |
| 77 | struct fwnode_handle *dev_fwnode; | ||
| 78 | bool asd_fwnode_is_ep; | ||
| 79 | bool sd_fwnode_is_ep; | ||
| 80 | struct device *dev; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Both the subdev and the async subdev can provide either an endpoint | ||
| 84 | * fwnode or a device fwnode. Start with the simple case of direct | ||
| 85 | * fwnode matching. | ||
| 86 | */ | ||
| 87 | if (sd->fwnode == asd->match.fwnode) | ||
| 88 | return true; | ||
| 89 | |||
| 90 | /* | ||
| 91 | * Otherwise, check if the sd fwnode and the asd fwnode refer to an | ||
| 92 | * endpoint or a device. If they're of the same type, there's no match. | ||
| 93 | * Technically speaking this checks if the nodes refer to a connected | ||
| 94 | * endpoint, which is the simplest check that works for both OF and | ||
| 95 | * ACPI. This won't make a difference, as drivers should not try to | ||
| 96 | * match unconnected endpoints. | ||
| 97 | */ | ||
| 98 | sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd->fwnode); | ||
| 99 | asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode); | ||
| 100 | |||
| 101 | if (sd_fwnode_is_ep == asd_fwnode_is_ep) | ||
| 102 | return false; | ||
| 103 | |||
| 104 | /* | ||
| 105 | * The sd and asd fwnodes are of different types. Get the device fwnode | ||
| 106 | * parent of the endpoint fwnode, and compare it with the other fwnode. | ||
| 107 | */ | ||
| 108 | if (sd_fwnode_is_ep) { | ||
| 109 | dev_fwnode = fwnode_graph_get_port_parent(sd->fwnode); | ||
| 110 | other_fwnode = asd->match.fwnode; | ||
| 111 | } else { | ||
| 112 | dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode); | ||
| 113 | other_fwnode = sd->fwnode; | ||
| 114 | } | ||
| 115 | |||
| 116 | fwnode_handle_put(dev_fwnode); | ||
| 117 | |||
| 118 | if (dev_fwnode != other_fwnode) | ||
| 119 | return false; | ||
| 120 | |||
| 121 | /* | ||
| 122 | * We have a heterogeneous match. Retrieve the struct device of the side | ||
| 123 | * that matched on a device fwnode to print its driver name. | ||
| 124 | */ | ||
| 125 | if (sd_fwnode_is_ep) | ||
| 126 | dev = notifier->v4l2_dev ? notifier->v4l2_dev->dev | ||
| 127 | : notifier->sd->dev; | ||
| 128 | else | ||
| 129 | dev = sd->dev; | ||
| 130 | |||
| 131 | if (dev && dev->driver) { | ||
| 132 | if (sd_fwnode_is_ep) | ||
| 133 | dev_warn(dev, "Driver %s uses device fwnode, incorrect match may occur\n", | ||
| 134 | dev->driver->name); | ||
| 135 | dev_notice(dev, "Consider updating driver %s to match on endpoints\n", | ||
| 136 | dev->driver->name); | ||
| 137 | } | ||
| 138 | |||
| 139 | return true; | ||
| 75 | } | 140 | } |
| 76 | 141 | ||
| 77 | static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) | 142 | static bool match_custom(struct v4l2_async_notifier *notifier, |
| 143 | struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) | ||
| 78 | { | 144 | { |
| 79 | if (!asd->match.custom.match) | 145 | if (!asd->match.custom.match) |
| 80 | /* Match always */ | 146 | /* Match always */ |
| @@ -91,7 +157,8 @@ static struct v4l2_async_subdev * · 10 unmodified lines | |||
| 91 | v4l2_async_find_match(struct v4l2_async_notifier *notifier, | 157 | v4l2_async_find_match(struct v4l2_async_notifier *notifier, |
| 92 | struct v4l2_subdev *sd) | 158 | struct v4l2_subdev *sd) |
| 93 | { | 159 | { |
| 94 | bool (*match)(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd); | 160 | bool (*match)(struct v4l2_async_notifier *notifier, |
| 161 | struct v4l2_subdev *sd, struct v4l2_async_subdev *asd); | ||
| 95 | struct v4l2_async_subdev *asd; | 162 | struct v4l2_async_subdev *asd; |
| 96 | 163 | ||
| 97 | list_for_each_entry(asd, ¬ifier->waiting, list) { | 164 | list_for_each_entry(asd, ¬ifier->waiting, list) { |
| @@ -116,7 +183,7 @@ v4l2_async_find_match(struct v4l2_async_notifier *notifier, · 18 unmodified lines | |||
| 116 | } | 183 | } |
| 117 | 184 | ||
| 118 | /* match cannot be NULL here */ | 185 | /* match cannot be NULL here */ |
| 119 | if (match(sd, asd)) | 186 | if (match(notifier, sd, asd)) |
| 120 | return asd; | 187 | return asd; |
| 121 | } | 188 | } |
| 122 | 189 | ||
| @@ -246,6 +246,9 @@ struct v4l2_format32 { · 245 unmodified lines | |||
| 246 | * @memory: buffer memory type | 246 | * @memory: buffer memory type |
| 247 | * @format: frame format, for which buffers are requested | 247 | * @format: frame format, for which buffers are requested |
| 248 | * @capabilities: capabilities of this buffer type. | 248 | * @capabilities: capabilities of this buffer type. |
| 249 | * @flags: additional buffer management attributes (ignored unless the | ||
| 250 | * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and | ||
| 251 | * configured for MMAP streaming I/O). | ||
| 249 | * @reserved: future extensions | 252 | * @reserved: future extensions |
| 250 | */ | 253 | */ |
| 251 | struct v4l2_create_buffers32 { | 254 | struct v4l2_create_buffers32 { |
| @@ -254,7 +257,8 @@ struct v4l2_create_buffers32 { · 2 unmodified lines | |||
| 254 | __u32 memory; /* enum v4l2_memory */ | 257 | __u32 memory; /* enum v4l2_memory */ |
| 255 | struct v4l2_format32 format; | 258 | struct v4l2_format32 format; |
| 256 | __u32 capabilities; | 259 | __u32 capabilities; |
| 257 | __u32 reserved[7]; | 260 | __u32 flags; |
| 261 | __u32 reserved[6]; | ||
| 258 | }; | 262 | }; |
| 259 | 263 | ||
| 260 | static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size) | 264 | static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size) |
| @@ -355,7 +359,8 @@ static int get_v4l2_create32(struct v4l2_create_buffers __user *p64, · 94 unmodified lines | |||
| 355 | { | 359 | { |
| 356 | if (!access_ok(p32, sizeof(*p32)) || | 360 | if (!access_ok(p32, sizeof(*p32)) || |
| 357 | copy_in_user(p64, p32, | 361 | copy_in_user(p64, p32, |
| 358 | offsetof(struct v4l2_create_buffers32, format))) | 362 | offsetof(struct v4l2_create_buffers32, format)) || |
| 363 | assign_in_user(&p64->flags, &p32->flags)) | ||
| 359 | return -EFAULT; | 364 | return -EFAULT; |
| 360 | return __get_v4l2_format32(&p64->format, &p32->format, | 365 | return __get_v4l2_format32(&p64->format, &p32->format, |
| 361 | aux_buf, aux_space); | 366 | aux_buf, aux_space); |
| @@ -417,6 +422,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers __user *p64, · 55 unmodified lines | |||
| 417 | copy_in_user(p32, p64, | 422 | copy_in_user(p32, p64, |
| 418 | offsetof(struct v4l2_create_buffers32, format)) || | 423 | offsetof(struct v4l2_create_buffers32, format)) || |
| 419 | assign_in_user(&p32->capabilities, &p64->capabilities) || | 424 | assign_in_user(&p32->capabilities, &p64->capabilities) || |
| 425 | assign_in_user(&p32->flags, &p64->flags) || | ||
| 420 | copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) | 426 | copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) |
| 421 | return -EFAULT; | 427 | return -EFAULT; |
| 422 | return __put_v4l2_format32(&p64->format, &p32->format); | 428 | return __put_v4l2_format32(&p64->format, &p32->format); |
| @@ -582,7 +582,10 @@ static void v4l_print_querymenu(const void *arg, bool write_only) · 581 unmodified lines | |||
| 582 | static void v4l_print_control(const void *arg, bool write_only) | 582 | static void v4l_print_control(const void *arg, bool write_only) |
| 583 | { | 583 | { |
| 584 | const struct v4l2_control *p = arg; | 584 | const struct v4l2_control *p = arg; |
| 585 | const char *name = v4l2_ctrl_get_name(p->id); | ||
| 585 | 586 | ||
| 587 | if (name) | ||
| 588 | pr_cont("name=%s, ", name); | ||
| 586 | pr_cont("id=0x%x, value=%d\n", p->id, p->value); | 589 | pr_cont("id=0x%x, value=%d\n", p->id, p->value); |
| 587 | } | 590 | } |
| 588 | 591 | ||
| @@ -594,12 +597,15 @@ static void v4l_print_ext_controls(const void *arg, bool write_only) · 5 unmodified lines | |||
| 594 | pr_cont("which=0x%x, count=%d, error_idx=%d, request_fd=%d", | 597 | pr_cont("which=0x%x, count=%d, error_idx=%d, request_fd=%d", |
| 595 | p->which, p->count, p->error_idx, p->request_fd); | 598 | p->which, p->count, p->error_idx, p->request_fd); |
| 596 | for (i = 0; i < p->count; i++) { | 599 | for (i = 0; i < p->count; i++) { |
| 600 | unsigned int id = p->controls[i].id; | ||
| 601 | const char *name = v4l2_ctrl_get_name(id); | ||
| 602 | |||
| 603 | if (name) | ||
| 604 | pr_cont(", name=%s", name); | ||
| 597 | if (!p->controls[i].size) | 605 | if (!p->controls[i].size) |
| 598 | pr_cont(", id/val=0x%x/0x%x", | 606 | pr_cont(", id/val=0x%x/0x%x", id, p->controls[i].value); |
| 599 | p->controls[i].id, p->controls[i].value); | ||
| 600 | else | 607 | else |
| 601 | pr_cont(", id/size=0x%x/%u", | 608 | pr_cont(", id/size=0x%x/%u", id, p->controls[i].size); |
| 602 | p->controls[i].id, p->controls[i].size); | ||
| 603 | } | 609 | } |
| 604 | pr_cont("\n"); | 610 | pr_cont("\n"); |
| 605 | } | 611 | } |
| @@ -2038,9 +2044,6 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, · 1432 unmodified lines | |||
| 2038 | 2044 | ||
| 2039 | if (ret) | 2045 | if (ret) |
| 2040 | return ret; | 2046 | return ret; |
| 2041 | |||
| 2042 | CLEAR_AFTER_FIELD(p, capabilities); | ||
| 2043 | |||
| 2044 | return ops->vidioc_reqbufs(file, fh, p); | 2047 | return ops->vidioc_reqbufs(file, fh, p); |
| 2045 | } | 2048 | } |
| 2046 | 2049 | ||
| @@ -2080,7 +2083,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, · 33 unmodified lines | |||
| 2080 | if (ret) | 2083 | if (ret) |
| 2081 | return ret; | 2084 | return ret; |
| 2082 | 2085 | ||
| 2083 | CLEAR_AFTER_FIELD(create, capabilities); | 2086 | CLEAR_AFTER_FIELD(create, flags); |
| 2084 | 2087 | ||
| 2085 | v4l_sanitize_format(&create->format); | 2088 | v4l_sanitize_format(&create->format); |
| 2086 | 2089 | ||
| @@ -556,7 +556,7 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, · 555 unmodified lines | |||
| 556 | ret = vb2_querybuf(vq, buf); | 556 | ret = vb2_querybuf(vq, buf); |
| 557 | 557 | ||
| 558 | /* Adjust MMAP memory offsets for the CAPTURE queue */ | 558 | /* Adjust MMAP memory offsets for the CAPTURE queue */ |
| 559 | if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) { | 559 | if (buf->memory == V4L2_MEMORY_MMAP && V4L2_TYPE_IS_CAPTURE(vq->type)) { |
| 560 | if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { | 560 | if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { |
| 561 | for (i = 0; i < buf->length; ++i) | 561 | for (i = 0; i < buf->length; ++i) |
| 562 | buf->m.planes[i].m.mem_offset | 562 | buf->m.planes[i].m.mem_offset |
| @@ -712,7 +712,7 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, · 149 unmodified lines | |||
| 712 | int ret; | 712 | int ret; |
| 713 | 713 | ||
| 714 | vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); | 714 | vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); |
| 715 | if (!V4L2_TYPE_IS_OUTPUT(vq->type) && | 715 | if (V4L2_TYPE_IS_CAPTURE(vq->type) && |
| 716 | (buf->flags & V4L2_BUF_FLAG_REQUEST_FD)) { | 716 | (buf->flags & V4L2_BUF_FLAG_REQUEST_FD)) { |
| 717 | dprintk("%s: requests cannot be used with capture buffers\n", | 717 | dprintk("%s: requests cannot be used with capture buffers\n", |
| 718 | __func__); | 718 | __func__); |
| @@ -729,7 +729,7 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, · 10 unmodified lines | |||
| 729 | * buffer as DONE with LAST flag since it won't be queued on the | 729 | * buffer as DONE with LAST flag since it won't be queued on the |
| 730 | * device. | 730 | * device. |
| 731 | */ | 731 | */ |
| 732 | if (!V4L2_TYPE_IS_OUTPUT(vq->type) && | 732 | if (V4L2_TYPE_IS_CAPTURE(vq->type) && |
| 733 | vb2_is_streaming(vq) && !vb2_start_streaming_called(vq) && | 733 | vb2_is_streaming(vq) && !vb2_start_streaming_called(vq) && |
| 734 | (v4l2_m2m_has_stopped(m2m_ctx) || v4l2_m2m_dst_buf_is_last(m2m_ctx))) | 734 | (v4l2_m2m_has_stopped(m2m_ctx) || v4l2_m2m_dst_buf_is_last(m2m_ctx))) |
| 735 | v4l2_m2m_force_last_buf_done(m2m_ctx, vq); | 735 | v4l2_m2m_force_last_buf_done(m2m_ctx, vq); |
| @@ -42,8 +42,6 @@ source "drivers/staging/media/tegra-video/Kconfig" · 41 unmodified lines | |||
| 42 | 42 | ||
| 43 | source "drivers/staging/media/ipu3/Kconfig" | 43 | source "drivers/staging/media/ipu3/Kconfig" |
| 44 | 44 | ||
| 45 | source "drivers/staging/media/soc_camera/Kconfig" | ||
| 46 | |||
| 47 | source "drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig" | 45 | source "drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig" |
| 48 | 46 | ||
| 49 | source "drivers/staging/media/rkisp1/Kconfig" | 47 | source "drivers/staging/media/rkisp1/Kconfig" |
| @@ -10,7 +10,6 @@ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ · 9 unmodified lines | |||
| 10 | obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ | 10 | obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ |
| 11 | obj-$(CONFIG_VIDEO_HANTRO) += hantro/ | 11 | obj-$(CONFIG_VIDEO_HANTRO) += hantro/ |
| 12 | obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ | 12 | obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ |
| 13 | obj-$(CONFIG_SOC_CAMERA) += soc_camera/ | ||
| 14 | obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0/ | 13 | obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0/ |
| 15 | obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rkisp1/ | 14 | obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rkisp1/ |
| 16 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ | 15 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ |
| @@ -105,9 +105,11 @@ struct allegro_buffer { · 104 unmodified lines | |||
| 105 | struct list_head head; | 105 | struct list_head head; |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | struct allegro_dev; | ||
| 108 | struct allegro_channel; | 109 | struct allegro_channel; |
| 109 | 110 | ||
| 110 | struct allegro_mbox { | 111 | struct allegro_mbox { |
| 112 | struct allegro_dev *dev; | ||
| 111 | unsigned int head; | 113 | unsigned int head; |
| 112 | unsigned int tail; | 114 | unsigned int tail; |
| 113 | unsigned int data; | 115 | unsigned int data; |
| @@ -128,14 +130,15 @@ struct allegro_dev { · 14 unmodified lines | |||
| 128 | struct regmap *regmap; | 130 | struct regmap *regmap; |
| 129 | struct regmap *sram; | 131 | struct regmap *sram; |
| 130 | 132 | ||
| 133 | const struct fw_info *fw_info; | ||
| 131 | struct allegro_buffer firmware; | 134 | struct allegro_buffer firmware; |
| 132 | struct allegro_buffer suballocator; | 135 | struct allegro_buffer suballocator; |
| 133 | 136 | ||
| 134 | struct completion init_complete; | 137 | struct completion init_complete; |
| 135 | 138 | ||
| 136 | /* The mailbox interface */ | 139 | /* The mailbox interface */ |
| 137 | struct allegro_mbox mbox_command; | 140 | struct allegro_mbox *mbox_command; |
| 138 | struct allegro_mbox mbox_status; | 141 | struct allegro_mbox *mbox_status; |
| 139 | 142 | ||
| 140 | /* | 143 | /* |
| 141 | * The downstream driver limits the users to 64 users, thus I can use | 144 | * The downstream driver limits the users to 64 users, thus I can use |
| @@ -204,6 +207,11 @@ struct allegro_channel { · 62 unmodified lines | |||
| 204 | unsigned int cpb_size; | 207 | unsigned int cpb_size; |
| 205 | unsigned int gop_size; | 208 | unsigned int gop_size; |
| 206 | 209 | ||
| 210 | struct allegro_buffer config_blob; | ||
| 211 | |||
| 212 | unsigned int num_ref_idx_l0; | ||
| 213 | unsigned int num_ref_idx_l1; | ||
| 214 | |||
| 207 | struct v4l2_ctrl *mpeg_video_h264_profile; | 215 | struct v4l2_ctrl *mpeg_video_h264_profile; |
| 208 | struct v4l2_ctrl *mpeg_video_h264_level; | 216 | struct v4l2_ctrl *mpeg_video_h264_level; |
| 209 | struct v4l2_ctrl *mpeg_video_h264_i_frame_qp; | 217 | struct v4l2_ctrl *mpeg_video_h264_i_frame_qp; |
| @@ -270,6 +278,7 @@ struct fw_info { · 60 unmodified lines | |||
| 270 | unsigned int mailbox_cmd; | 278 | unsigned int mailbox_cmd; |
| 271 | unsigned int mailbox_status; | 279 | unsigned int mailbox_status; |
| 272 | size_t mailbox_size; | 280 | size_t mailbox_size; |
| 281 | enum mcu_msg_version mailbox_version; | ||
| 273 | size_t suballocator_size; | 282 | size_t suballocator_size; |
| 274 | }; | 283 | }; |
| 275 | 284 | ||
| @@ -281,7 +290,17 @@ static const struct fw_info supported_firmware[] = { · 5 unmodified lines | |||
| 281 | .mailbox_cmd = 0x7800, | 290 | .mailbox_cmd = 0x7800, |
| 282 | .mailbox_status = 0x7c00, | 291 | .mailbox_status = 0x7c00, |
| 283 | .mailbox_size = 0x400 - 0x8, | 292 | .mailbox_size = 0x400 - 0x8, |
| 293 | .mailbox_version = MCU_MSG_VERSION_2018_2, | ||
| 284 | .suballocator_size = SZ_16M, | 294 | .suballocator_size = SZ_16M, |
| 295 | }, { | ||
| 296 | .id = 14680, | ||
| 297 | .id_codec = 126572, | ||
| 298 | .version = "v2019.2", | ||
| 299 | .mailbox_cmd = 0x7000, | ||
| 300 | .mailbox_status = 0x7800, | ||
| 301 | .mailbox_size = 0x800 - 0x8, | ||
| 302 | .mailbox_version = MCU_MSG_VERSION_2019_2, | ||
| 303 | .suballocator_size = SZ_32M, | ||
| 285 | }, | 304 | }, |
| 286 | }; | 305 | }; |
| 287 | 306 | ||
| @@ -583,12 +602,20 @@ static void allegro_free_buffer(struct allegro_dev *dev, · 295 unmodified lines | |||
| 583 | * Mailbox interface to send messages to the MCU. | 602 | * Mailbox interface to send messages to the MCU. |
| 584 | */ | 603 | */ |
| 585 | 604 | ||
| 586 | static int allegro_mbox_init(struct allegro_dev *dev, | 605 | static void allegro_mcu_interrupt(struct allegro_dev *dev); |
| 587 | struct allegro_mbox *mbox, | 606 | static void allegro_handle_message(struct allegro_dev *dev, |
| 588 | unsigned int base, size_t size) | 607 | union mcu_msg_response *msg); |
| 608 | |||
| 609 | static struct allegro_mbox *allegro_mbox_init(struct allegro_dev *dev, | ||
| 610 | unsigned int base, size_t size) | ||
| 589 | { | 611 | { |
| 612 | struct allegro_mbox *mbox; | ||
| 613 | |||
| 614 | mbox = devm_kmalloc(&dev->plat_dev->dev, sizeof(*mbox), GFP_KERNEL); | ||
| 590 | if (!mbox) | 615 | if (!mbox) |
| 591 | return -EINVAL; | 616 | return ERR_PTR(-ENOMEM); |
| 617 | |||
| 618 | mbox->dev = dev; | ||
| 592 | 619 | ||
| 593 | mbox->head = base; | 620 | mbox->head = base; |
| 594 | mbox->tail = base + 0x4; | 621 | mbox->tail = base + 0x4; |
| @@ -599,52 +626,37 @@ static int allegro_mbox_init(struct allegro_dev *dev, · 4 unmodified lines | |||
| 599 | regmap_write(dev->sram, mbox->head, 0); | 626 | regmap_write(dev->sram, mbox->head, 0); |
| 600 | regmap_write(dev->sram, mbox->tail, 0); | 627 | regmap_write(dev->sram, mbox->tail, 0); |
| 601 | 628 | ||
| 602 | return 0; | 629 | return mbox; |
| 603 | } | 630 | } |
| 604 | 631 | ||
| 605 | static int allegro_mbox_write(struct allegro_dev *dev, | 632 | static int allegro_mbox_write(struct allegro_mbox *mbox, |
| 606 | struct allegro_mbox *mbox, void *src, size_t size) | 633 | const u32 *src, size_t size) |
| 607 | { | 634 | { |
| 608 | struct mcu_msg_header *header = src; | 635 | struct regmap *sram = mbox->dev->sram; |
| 609 | unsigned int tail; | 636 | unsigned int tail; |
| 610 | size_t size_no_wrap; | 637 | size_t size_no_wrap; |
| 611 | int err = 0; | 638 | int err = 0; |
| 639 | int stride = regmap_get_reg_stride(sram); | ||
| 612 | 640 | ||
| 613 | if (!src) | 641 | if (!src) |
| 614 | return -EINVAL; | 642 | return -EINVAL; |
| 615 | 643 | ||
| 616 | if (size > mbox->size) { | 644 | if (size > mbox->size) |
| 617 | v4l2_err(&dev->v4l2_dev, | ||
| 618 | "message (%zu bytes) too large for mailbox (%zu bytes)\n", | ||
| 619 | size, mbox->size); | ||
| 620 | return -EINVAL; | 645 | return -EINVAL; |
| 621 | } | ||
| 622 | |||
| 623 | if (header->length != size - sizeof(*header)) { | ||
| 624 | v4l2_err(&dev->v4l2_dev, | ||
| 625 | "invalid message length: %u bytes (expected %zu bytes)\n", | ||
| 626 | header->length, size - sizeof(*header)); | ||
| 627 | return -EINVAL; | ||
| 628 | } | ||
| 629 | |||
| 630 | v4l2_dbg(2, debug, &dev->v4l2_dev, | ||
| 631 | "write command message: type %s, body length %d\n", | ||
| 632 | msg_type_name(header->type), header->length); | ||
| 633 | 646 | ||
| 634 | mutex_lock(&mbox->lock); | 647 | mutex_lock(&mbox->lock); |
| 635 | regmap_read(dev->sram, mbox->tail, &tail); | 648 | regmap_read(sram, mbox->tail, &tail); |
| 636 | if (tail > mbox->size) { | 649 | if (tail > mbox->size) { |
| 637 | v4l2_err(&dev->v4l2_dev, | ||
| 638 | "invalid tail (0x%x): must be smaller than mailbox size (0x%zx)\n", | ||
| 639 | tail, mbox->size); | ||
| 640 | err = -EIO; | 650 | err = -EIO; |
| 641 | goto out; | 651 | goto out; |
| 642 | } | 652 | } |
| 643 | size_no_wrap = min(size, mbox->size - (size_t)tail); | 653 | size_no_wrap = min(size, mbox->size - (size_t)tail); |
| 644 | regmap_bulk_write(dev->sram, mbox->data + tail, src, size_no_wrap / 4); | 654 | regmap_bulk_write(sram, mbox->data + tail, |
| 645 | regmap_bulk_write(dev->sram, mbox->data, | 655 | src, size_no_wrap / stride); |
| 646 | src + size_no_wrap, (size - size_no_wrap) / 4); | 656 | regmap_bulk_write(sram, mbox->data, |
| 647 | regmap_write(dev->sram, mbox->tail, (tail + size) % mbox->size); | 657 | src + (size_no_wrap / sizeof(*src)), |
| 658 | (size - size_no_wrap) / stride); | ||
| 659 | regmap_write(sram, mbox->tail, (tail + size) % mbox->size); | ||
| 648 | 660 | ||
| 649 | out: | 661 | out: |
| 650 | mutex_unlock(&mbox->lock); | 662 | mutex_unlock(&mbox->lock); |
| @@ -652,40 +664,32 @@ out: · 1 unmodified line | |||
| 652 | return err; | 664 | return err; |
| 653 | } | 665 | } |
| 654 | 666 | ||
| 655 | static ssize_t allegro_mbox_read(struct allegro_dev *dev, | 667 | static ssize_t allegro_mbox_read(struct allegro_mbox *mbox, |
| 656 | struct allegro_mbox *mbox, | 668 | u32 *dst, size_t nbyte) |
| 657 | void *dst, size_t nbyte) | ||
| 658 | { | 669 | { |
| 659 | struct mcu_msg_header *header; | 670 | struct { |
| 671 | u16 length; | ||
| 672 | u16 type; | ||
| 673 | } __attribute__ ((__packed__)) *header; | ||
| 674 | struct regmap *sram = mbox->dev->sram; | ||
| 660 | unsigned int head; | 675 | unsigned int head; |
| 661 | ssize_t size; | 676 | ssize_t size; |
| 662 | size_t body_no_wrap; | 677 | size_t body_no_wrap; |
| 678 | int stride = regmap_get_reg_stride(sram); | ||
| 663 | 679 | ||
| 664 | regmap_read(dev->sram, mbox->head, &head); | 680 | regmap_read(sram, mbox->head, &head); |
| 665 | if (head > mbox->size) { | 681 | if (head > mbox->size) |
| 666 | v4l2_err(&dev->v4l2_dev, | ||
| 667 | "invalid head (0x%x): must be smaller than mailbox size (0x%zx)\n", | ||
| 668 | head, mbox->size); | ||
| 669 | return -EIO; | 682 | return -EIO; |
| 670 | } | ||
| 671 | 683 | ||
| 672 | /* Assume that the header does not wrap. */ | 684 | /* Assume that the header does not wrap. */ |
| 673 | regmap_bulk_read(dev->sram, mbox->data + head, | 685 | regmap_bulk_read(sram, mbox->data + head, |
| 674 | dst, sizeof(*header) / 4); | 686 | dst, sizeof(*header) / stride); |
| 675 | header = dst; | 687 | header = (void *)dst; |
| 676 | size = header->length + sizeof(*header); | 688 | size = header->length + sizeof(*header); |
| 677 | if (size > mbox->size || size & 0x3) { | 689 | if (size > mbox->size || size & 0x3) |
| 678 | v4l2_err(&dev->v4l2_dev, | ||
| 679 | "invalid message length: %zu bytes (maximum %zu bytes)\n", | ||
| 680 | header->length + sizeof(*header), mbox->size); | ||
| 681 | return -EIO; | 690 | return -EIO; |
| 682 | } | 691 | if (size > nbyte) |
| 683 | if (size > nbyte) { | ||
| 684 | v4l2_err(&dev->v4l2_dev, | ||
| 685 | "destination buffer too small: %zu bytes (need %zu bytes)\n", | ||
| 686 | nbyte, size); | ||
| 687 | return -EINVAL; | 692 | return -EINVAL; |
| 688 | } | ||
| 689 | 693 | ||
| 690 | /* | 694 | /* |
| 691 | * The message might wrap within the mailbox. If the message does not | 695 | * The message might wrap within the mailbox. If the message does not |
| @@ -698,24 +702,84 @@ static ssize_t allegro_mbox_read(struct allegro_dev *dev, · 6 unmodified lines | |||
| 698 | */ | 702 | */ |
| 699 | body_no_wrap = min((size_t)header->length, | 703 | body_no_wrap = min((size_t)header->length, |
| 700 | (size_t)(mbox->size - (head + sizeof(*header)))); | 704 | (size_t)(mbox->size - (head + sizeof(*header)))); |
| 701 | regmap_bulk_read(dev->sram, mbox->data + head + sizeof(*header), | 705 | regmap_bulk_read(sram, mbox->data + head + sizeof(*header), |
| 702 | dst + sizeof(*header), body_no_wrap / 4); | 706 | dst + (sizeof(*header) / sizeof(*dst)), |
| 703 | regmap_bulk_read(dev->sram, mbox->data, | 707 | body_no_wrap / stride); |
| 704 | dst + sizeof(*header) + body_no_wrap, | 708 | regmap_bulk_read(sram, mbox->data, |
| 705 | (header->length - body_no_wrap) / 4); | 709 | dst + (sizeof(*header) + body_no_wrap) / sizeof(*dst), |
| 706 | 710 | (header->length - body_no_wrap) / stride); | |
| 707 | regmap_write(dev->sram, mbox->head, (head + size) % mbox->size); | ||
| 708 | 711 | ||
| 709 | v4l2_dbg(2, debug, &dev->v4l2_dev, | 712 | regmap_write(sram, mbox->head, (head + size) % mbox->size); |
| 710 | "read status message: type %s, body length %d\n", | ||
| 711 | msg_type_name(header->type), header->length); | ||
| 712 | 713 | ||
| 713 | return size; | 714 | return size; |
| 714 | } | 715 | } |
| 715 | 716 | ||
| 716 | static void allegro_mcu_interrupt(struct allegro_dev *dev) | 717 | /** |
| 718 | * allegro_mbox_send() - Send a message via the mailbox | ||
| 719 | * @mbox: the mailbox which is used to send the message | ||
| 720 | * @msg: the message to send | ||
| 721 | */ | ||
| 722 | static int allegro_mbox_send(struct allegro_mbox *mbox, void *msg) | ||
| 717 | { | 723 | { |
| 718 | regmap_write(dev->regmap, AL5_MCU_INTERRUPT, BIT(0)); | 724 | struct allegro_dev *dev = mbox->dev; |
| 725 | ssize_t size; | ||
| 726 | int err; | ||
| 727 | u32 *tmp; | ||
| 728 | |||
| 729 | tmp = kzalloc(mbox->size, GFP_KERNEL); | ||
| 730 | if (!tmp) { | ||
| 731 | err = -ENOMEM; | ||
| 732 | goto out; | ||
| 733 | } | ||
| 734 | |||
| 735 | size = allegro_encode_mail(tmp, msg); | ||
| 736 | |||
| 737 | err = allegro_mbox_write(mbox, tmp, size); | ||
| 738 | kfree(tmp); | ||
| 739 | if (err) | ||
| 740 | goto out; | ||
| 741 | |||
| 742 | allegro_mcu_interrupt(dev); | ||
| 743 | |||
| 744 | out: | ||
| 745 | return err; | ||
| 746 | } | ||
| 747 | |||
| 748 | /** | ||
| 749 | * allegro_mbox_notify() - Notify the mailbox about a new message | ||
| 750 | * @mbox: The allegro_mbox to notify | ||
| 751 | */ | ||
| 752 | static void allegro_mbox_notify(struct allegro_mbox *mbox) | ||
| 753 | { | ||
| 754 | struct allegro_dev *dev = mbox->dev; | ||
| 755 | union mcu_msg_response *msg; | ||
| 756 | ssize_t size; | ||
| 757 | u32 *tmp; | ||
| 758 | int err; | ||
| 759 | |||
| 760 | msg = kmalloc(sizeof(*msg), GFP_KERNEL); | ||
| 761 | if (!msg) | ||
| 762 | return; | ||
439 more lines aren’t shown here.
This diff is large: its 518 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 21 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 130 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 262 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 54 lines aren’t shown here.
This diff is large: its 254 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 493 lines aren’t shown here.
This diff is large: its 854 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 2165 lines aren’t shown here.
This diff is large: its 530 lines aren’t shown here.
This diff is large: its 1009 lines aren’t shown here.
This diff is large: its 1086 lines aren’t shown here.
This diff is large: its 993 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 20 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 398 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.